Friday, 22 October 2021

[Golang] How To Work With Defer In Golang Tutorial

Today we are going to learn about defer in golang. What Defer does and how it works we are going to see that via implementation of some code which is focused on defer keyword of golang.

So before starting let's understand the defer via it's definition then we are going to implement some code on it.


What if Defer? 

Defer statement is used to execute a function call just before the surrounding function where the defer statement is present returns.The definition might seem complex but it's pretty simple to understand by means of an example.

We have finished the definition reading part and via it we understand that a defer runs before exiting or returning from a function, means the last second last step of function which have defer keyword used.

Now let's write some code to understand it in via code.

EXAMPLE

package main

import (
"fmt"
)

func sliceToName(s []string) {
var str string
fmt.Println("Started joining slice into string")
for _, is := range s {
str += is
}
fmt.Println("Create name from slice is", str)

}

func main() {
defer fmt.Println("Finished joining slice into string")
s := []string{"G", "O", "L", "A", "N", "G"}
sliceToName(s)
}

Run in playground 

The above code is a simple program to combine the slice of string into a single string to make it a full name.I know I can use the join function as well from the string package but for testing we decided to make our own.The sliceToName function takes a string slice as a function parameter and prints the combined values of a slice into string. The most important line is defer which we have in our main function as you can see we have used fmt.Println  as before that we have added defer keyword in it so now let's run the code and the sequence of the code execution.


Started joining slice into string
Create name from slice is GOLANG
Finished joining slice into string
The sliceToName function starts executing and prints the first two lines of the above output and before it could return our defer function which is in main function executes and prints the text Finished joining slice into string.


Now let's try to move this defer from main function to a seperate function and call that function from sliceToName and then let's see what will be the output of that code will be.


package main

import (
"fmt"
)

func DeferedFinished() {
fmt.Println("Finished joining slice into string")
}


func sliceToName(s []string) {
defer DeferedFinished()
var str string
fmt.Println("Started joining slice into string")
for _, is := range s {
str += is
}
fmt.Println("Create name from slice is", str)
}

func main() {
s := []string{"G", "O", "L", "A", "N", "G"}
sliceToName(s)
}

So you can see we have seperated our print statement from main function to a seperate function and all of the logic is same except the DeferedFinished function we have created it and calling it in our sliceToName function with the defer keyword now let's check the output.

Started joining slice into string
Create name from slice is GOLANG
Finished joining slice into string

The above output is also same as we have for the first example so now you understand how defer works now.


Multiple Defer Keywords Case

Now Let's try to use multiple defer keywords with multiple print statement and then check the order of the execution of the code how they works.

Let's check the code first without using the defer keyword.

EXAMPLE 1

package main

import (
"fmt"
)

func deferSequence(i int) {
fmt.Println("Defer Sequence Number", i)
}

func main() {
deferSequence(5)
deferSequence(4)
deferSequence(3)
deferSequence(2)
deferSequence(1)
}

As you can see we have called deferSequence function five times and have given numbers as well to check the output in which sequence are they running. Now let's check the output first.

Defer Sequence Number 5
Defer Sequence Number 4
Defer Sequence Number 3
Defer Sequence Number 2
Defer Sequence Number 1

The above output result is in sequence without using defer keyword.

Now check the another approach which have defer keyword included in all functions which is called from main.

EXAMPLE 2

package main

import (
"fmt"
)

func deferSequence(i int) {
fmt.Println("Defer Sequence Number", i)
}

func main() {
defer deferSequence(5)
defer deferSequence(4)
defer deferSequence(3)
defer deferSequence(2)
defer deferSequence(1)
}

So in above code we have added defer keyword for each function now let's check the output.

Defer Sequence Number 1
Defer Sequence Number 2
Defer Sequence Number 3
Defer Sequence Number 4
Defer Sequence Number 5
So as you can see the order of the execution of each function now have reversed or as we can say it follows Last In First Out - LIFO order.

 

Uses Defer to close files as well

we also uses defer keyword to close the open files as well. You can see the code which is written below

EXAMPLE

package main

import (
    "fmt"
    "os"
)


func isError(err error) bool {
    if err != nil {
        fmt.Println(err.Error())
    }
    return (err != nil)
}

func main() {
    var path = "app.txt"
    fmt.Println("Opening a file ")
    var file, err = os.OpenFile(path, os.O_RDWR, 0644)
    if isError(err) {
        return
    }
    defer file.Close()
}


Using Defer in Loop.

So we are also trying to use defer is loop as well via this approach we are going to reverse a string.

package main

import (  
    "fmt"
)

func main() {  
    name := "Kuldeep"
    fmt.Printf("Original String: %s\n", name)
    fmt.Printf("Reversed String: ")
    for _, v := range []rune(name) {
        defer fmt.Printf("%c", v)
    }
}

In the above code we have a name variable and then we are running a loop on it before running loop we are converting it to rune so we can run loop on each characters which is rune type now and the with the help of formatter we are printing getting the characters of that run and also we have added defer keyword as well in that print statement.

Original String: Kuldeep
Reversed String: peedluK

So we can see the above output which is reversed with the help of the defer keyword.

Labels:

Sunday, 17 October 2021

[Golang] How To Work With Maps In Golang Tutorial

What is Map In Golang?

Maps are a convenient and powerful built-in data structure that associate values of one type (the key) with values of another type (the element or value). The key can be of any type for which the equality operator is defined, such as integers, floating point and complex numbers, strings, pointers, interfaces (as long as the dynamic type supports equality), structs and arrays. Slices cannot be used as map keys, because equality is not defined on them. Like slices, maps hold references to an underlying data structure. If you pass a map to a function that changes the contents of the map, the changes will be visible in the caller.

Maps can be constructed using the usual composite literal syntax with colon-separated key-value pairs, so it's easy to build them during initialization.

For more context you can compare golangs' map as pythons' dictionary and as well nodejs' object.


How to Create Map?

A map can be created by passing the type of key and value to the make function and as well as using direct way with map keyword. The following is the syntax to create a new map with make.

make(map[type of key]type of value)  
map[type of key]type of value{}
usersVisited := make(map[string]int)


The Above he have created a map with the help of make function which is usersVisited so this map is going to store the values via ip and count of that ip's visits as int each time we're going to increase that number whenever some request comes from the ip which exists in usersVisited map.



    package main

    import "fmt"

    func main() {
        usersVisited := make(map[string]int)
        fmt.Println(usersVisited)
    }



So this is the code to declare the map let's run it and check what result it gives us.

map[]
we haven't added any key and value yet so the output of the map is empty.


Let's Add Key and Values in Map

The Syntax for adding new item in map is same as we do for the arrays and slices.
The Program below adds some new entries in usersVisited map.

    
    package main

    import "fmt"

    func main() {
        usersVisited := make(map[string]int)
        usersVisited["127.0.0.1"] = 1
        usersVisited["127.0.0.2"] = 2
        usersVisited["127.0.0.3"] = 3
        usersVisited["127.0.0.4"] = 4
        fmt.Println(usersVisited)    
    }




We have added four testing entries and the corresponding counts as well as.

The above program prints

map[127.0.0.1:1 127.0.0.2:2 127.0.0.3:3 127.0.0.4:4]

Initialization and Declaration At the Same Time.

It is possible us to initialize and declare the map at the same time in golang as we have code above for declaration.

Let's see the code for this step

    
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        fmt.Println(usersVisited)
    }




The above program declares usersVisited map and adds four entries in it as well.

Note: You can  Add more keys and values after declaration and initialization as well, As we did before this example


Note : You can use any data type which exists in golang as your key and value type it depends on us which type's requirement we have, even you can use interfaces and structs as well. 


Zero Value of a Map

Zero value of a map is nil, and it if you try to add entries in nil map it can cause error or you can say a panic error. Hence the map has to be initialize before adding any entries or key and values in it.

Let's check which type of error it will going to give us.

    
    package main

    import "fmt"

    func main() {
        var usersVisited map[string]int
        usersVisited["127.0.0.1"] = 1
        fmt.Println(usersVisited)
    }




In the above program we are adding new key and value into usersVisited map.

Now Let's Check the output of it.

panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
        C:/Users/Kuldeep/Desktop/Youtube/golang-map/n.go:7 +0x56
exit status 2
So we have got the panic which pointing to the same issue as we thought


Retrieving Values from Map using Keys

We already have added few entries in our code so let's try to retrieve counts of each ip using the keys(ip string).

Syntax is to retrieve values from map is map[key].

Let's write the code for more context.

    
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        ip := "127.0.0.4"

        visitedCount := usersVisited[ip]
        fmt.Printf("IP %s\n%d Times Visited", ip, visitedCount)
    }



The code written above is simple. We have a ip address and we are just passing ip address into map and getting the count from it for that passed ip address.

IP 127.0.0.4
4 Times Visited

Key Not Exists In Map

So in this case we are about to check what output or error we are going to get if the key we passes to the map is not exists in map.

  
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        ip := "127.0.0.5"

        visitedCount := usersVisited[ip]
        fmt.Printf("IP %s\n%d Times Visited", ip, visitedCount)
    }



So the code written above is just doing the same process as we learn before, just passing key but this key isn't exists.

Let's see the output

IP 127.0.0.5
0 Times Visited
So the output of this is 0 for that so now we knows for non existing keys map doesn't gives any error just returns the empty as we have passes int type that's why it's zero if you try with string it will going to return blank or empty value for string.


Checking if Key Exists

In the above section we learned that when a key is not present, the zero value of the type will be returned. This doesn't help when we want to find out whether the key actually exists in the map.


For example we want to know if key exists in usersVisited maps or not so we can follow this step.

value, exists := map[key] 

The above code is the syntax to check if a key exists in a map. if it exists the the exists variable will be going to true and the value of that key is store in value variable as we have in above syntax.

    
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        ip := "127.0.0.5"

        visitedCount, exists := usersVisited[ip]
        if !exists {
            fmt.Printf("%s key not found", ip)
            return
        }
        fmt.Printf("IP %s\n%d Times Visited", ip, visitedCount)
    }




In the above code you can see we have added the same step to get the value and as well as to check if it exists or not.

We have added condition as well as to check if the exists is false or not if false then we're printing the not found statement.

Let's check the output

127.0.0.5 key not found 

Running Loop Over Map

The range form of the for loop is used to iterate over all elements of a map.


    
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        fmt.Println("Content of the usersVisited Map")
        for key, value := range usersVisited {
            fmt.Printf("userVisited[%s] = %d\n", key, value)
        }
    }




Output of the above code

Content of the usersVisited Map
userVisited[127.0.0.1] = 1
userVisited[127.0.0.2] = 2
userVisited[127.0.0.3] = 3
userVisited[127.0.0.4] = 4

Note :- One important fact is that the order of the retrieval of values from a map when using for range is not guaranteed to be the same for each execution of the program. It is also not the same as the order in which the elements were added to the map


Updating Value of a Key in Map

There is one more things which is more important you can update the values of any key at anytime in a map.

Let's try to update the value of 127.0.0.1 IP  from 1 to 2.


    
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        ip := "127.0.0.1"

        _, exists := usersVisited[ip]
        if !exists {
            userVisited[ip] = 1
        }
        usersVisited[ip]++

        fmt.Printf("IP %s\n%d Times Visited", ip, usersVisited[ip])
    }




So we have followed the same step for this as well as.
First we have checked for the key if key is not exists then we are adding new entry in our usersVisited map other wise increasing the count of our value for that ip address(Key).

Let's Check Output

IP 127.0.0.1
2 Times Visited

Deleting Entries From a Map

delete(map, key) is the syntax to delete key from a map. The delete function does not return any value.


 
    package main

    import "fmt"

    func main() {
        usersVisited := map[string]int{
            "127.0.0.1": 1,
            "127.0.0.2": 2,
            "127.0.0.3": 3,
            "127.0.0.4": 4,
        }

        fmt.Println("map before deleting entry", usersVisited)
        delete(usersVisited, "127.0.0.1")
        fmt.Println("map after deleting entry", usersVisited)
    }




The above program deletes the key(ip address) 127.0.0.1 from the map

Let's check the output

map before deleting entry map[127.0.0.1:1 127.0.0.2:2 127.0.0.3:3 127.0.0.4:4]
map after deleting entry map[127.0.0.2:2 127.0.0.3:3 127.0.0.4:4]




THANKS FOR READING





Labels:

Saturday, 16 October 2021

How To Create HTTP Server In Golang

The HTTP services in golang isn't complex at all. The HTTP package makes it easier to write or create a HTTP services without facing an major issues as compare to other programming languages. In this post we will going to create a HTTP server with the help of the golangs' http package.


Loading The Package(net/http) We Need

Before working on the server we needed to import the http package. It contains client and server implementation of HTTP.


import "net/http"


Simple HTTP server Creation

To Create a simple HTTP server we need to create endpoints as well as. In Go, we need to use handler functions that will handles different routers whenever they are called. Here is a simple server that listens on port 8000. So the endpoint is simple which is the main index or you can say home which we denotes via this characters "/".


package main
 
import (
    "fmt"
    "net/http"
)
 
func main() {
    // handle route using handler function
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Simple http server!")
    })
 
    // listen to port
    http.ListenAndServe(":8000", nil)
}


Now let's try to access the port number 8000 with the localhost you can follow as in below

simple http server golang


The Server is Running


Creating Multiple Routes

We can creating multiple router we need, To create multiple routes we just need to provide the path and the function which is going to invoke whenever endpoints get's any hit. Let's see how to create multiple endpoints.


    package main

    import (
        "fmt"
        "net/http"
    )

    func main() {
        // handle route using handler function
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Simple http server!")
        })

        http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "It's About Endpoint!")
        })

        http.HandleFunc("/contact", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "It's Contact Endpoint!")
        })

        http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
            name := r.URL.Query().Get("name")
            if name == "" {
                name = "Anonymous"
            }
            n := fmt.Sprintf("Hello %s", name)
            fmt.Fprintf(w, n)
        })

        // listen to port
        http.ListenAndServe(":8000", nil)
    }



Here we have added three more endpoints and each endpoint is printing something so let's start checking the results of endpoints one by one

When we access the about’ route we get different results.

It can be seen, that each route is handled by different handlers.

You can see at the last endpoint i have my name which is coming from backend after I have provided it into the endpoint this the called the query parameters in url. user endpoint also have one condition if the query parameter is blank or not used then the answer of the endpoint will going to be changed from name to anonymuse user let's check this result as well.

So now you guys know how we can also use qurey parameters as well from endpoint to make our output even more dynamic as per each requests.

Second Approach To Create HTTP Server

A mux is a multiplexer. Go has a type servemux defined in http package which is a request multiplexer. Here’s how we can use it for different paths. Here we are using the io package to send results.


   
   package main

    import (
        "fmt"
        "net/http"
    )

    func main() {

        mux := http.NewServeMux()

        // handle route using handler function
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Simple http server!")
        })

        mux.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "It's About Endpoint!")
        })

        mux.HandleFunc("/contact", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "It's Contact Endpoint!")
        })

        mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
            name := r.URL.Query().Get("name")
            if name == "" {
                name = "Anonymous"
            }
            n := fmt.Sprintf("Hello %s", name)
            fmt.Fprintf(w, n)
        })

        // listen to port
        http.ListenAndServe(":8000", mux)
    }

If You Find It Usefull and want me to create more on it please don't forget to support me: Support Me

Labels: