Notes on Go Structure Tags

Go has a feature to create a user-defined type with struct. Go also allows the program to specify meta-information with structure field.
This meta-information is called Tags. A tag usually helps in packaging/unpacking a user-defined type structure.

  package main

  import (
      "encoding/json"
      "fmt"
  )

  type Test struct {
      // json tags indicate the key name to use in json data
      Name    string `json:"myname"`
      Country string `json:"region"`
  }

  func main() {
      // The order of json need not match the order of structure fields.
      p := map[string]string{"region": "earth", "myname": "hello"}

      marshalled, err := json.Marshal(p)
      fmt.Println(marshalled, err)

      // get the var back from marshalled data
      var m Test
      json.Unmarshal(marshalled, &m)
      fmt.Printf("name=%v\n", m.Name)
      fmt.Printf("name=%v\n", m.Country)
  }

Why should I use json tags

  • The benefit of json tags is the flexibility to marshal with either a JSON or a struct.
  • JSON input for marshaling is convenient and flexible with elements ordering.

Reference

Advertisements

Golang: HTTP Client & Server with Query Params

Client

func TestDelete(id string, registered bool) {
      path := "http://localhost:8085/v1/shops"

      // Create client
      client := &http.Client{}

      // Create request
      req, err := http.NewRequest("DELETE", path, nil)
      if err != nil {
          fmt.Println(err)
          return
      }

      q := req.URL.Query()
      q.Add("id", r.UID)
      q.Add("registered", strconv.FormatBool(registered))
      req.URL.RawQuery = q.Encode()

      fmt.Println(req.URL.String())

      // Fetch Request
      resp, err := client.Do(req)
      if err != nil {
          fmt.Println(err)
          return
      }
      defer resp.Body.Close()

      // Read Response Body
      respBody, err := ioutil.ReadAll(resp.Body)
      if err != nil {
          fmt.Println(err)
          return
      }
      
      fmt.Printf("response=%v body=%v", resp, respBody)
      
      // the server returns a slice in response body
      var out []string
      json.Unmarshal(respBody, &out)
      fmt.Printf("response=%s", out)
  }

Server

var ( 
    errQP = errors.New("query param error")
)

func handleDelete(r *http.Request) (*response, error) {
	uid := r.URL.Query().Get("id")
	registration := r.URL.Query().Get("registration")
	if uid == "" || legacy == "" {
		glog.Errorf("handleDeletes: Url Param missing uid=%s registration=%s", uid, registration)
		return nil, errQP
	}

	isRegistered, err := strconv.ParseBool(registered)
	if err != nil {
		glog.Errorf("handleDelete: failed to parse id=%s registration=%s", uid, registration)
		return nil, err
	}
	// deletedShops is a slice
	deletedShops, err := deleteShops(id, isRegistered)
	if err != nil {
		glog.Errorf("handleDelete: failed id=%s registration=%v err=%s", id, isRegistered, err)
		return nil, err
	}

	return &response{
		status: 200,
		body:   deletedShops,
	}, nil
}

Points to Note

  • The above code allows a client to encode query params in a request.
  • The Client gets a slice in response.

Golang: Switch-case does not fall through!

Unlike C/C++ switch-case statements, Golang switch case does not fall through.

package main
import (
	"fmt"
)

func main() {
	fmt.Print("Go runs on ")
	os := "darwin"
	switch os {
	case "darwin":
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
	}
}

The above code does not print anything!

package main
import (
	"fmt"
)

func main() {
	fmt.Print("Go runs on ")
	os := "darwin"
	switch os {
	case "darwin":
	fallthrough
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
	}
}

You have to add fallthrough statement to make it work. The above code prints Linux.

Golang Type Assertions: Dynamic Type Checking

Type Assertions

Go supports dynamic type checking of variables. If the type of a variable is unknown till run-time, type assertions can run a validity check.

// getRequest definition
struct getRequest {
    name string
}
// Declare a void (anonymous) type variable
request interface{}

// Checking if variable request is not nil && 
// has type getRequest. 
request.(getRequest)

Summary

  • Type Assertion does runtime type check of a variable.
  • It also checks that value is non-nil.
  • Return true on success, false otherwise.

References

Written with StackEdit.

Why Using Golang sync Pool is a Bad Idea?

Not an absolutely bad idea, but you need a careful understanding before using sync Pool.

Golang sync Pool is used to create a self-managed object pool, with just New/Get/Set functions. The Pool implementation uses a mutex based locking for thread-safe operations from multiple Go routines.

Design Principles
  • Golang sync. Pool use garbage collection to manage objects. The pool is essentially a list of user-defined blob objects that are GC’ed periodically.
  • The application uses Get/Put for using an object from the Pool.
  • The application defines a New method to create a new object.
  • The application does not bother about object memory management.
  • Unreferenced that is objects present in the Pool at a given time is GC’ed.
  • There is no finalizer for objects deletion.
  • Get randomly selected object from the list; if no object is available, creates a new object and returns it.
  • Put places an object back to the Pool.
  • The design wants to avoid hotspots and randomize object selections in Put and Get operations. So, Put and Get calls may not be co-related.
    • A Put op may randomly return without placing the object back to the Pool.
    • This intentional delay helps the Get to pick a new object.
What are Potential Problems with Pool
  • If the object has allocated resources (socket, buffer), there is no way to free them!
  • If the application has got an object and starts processing it with async operations, there is a risk of data corruption if the application returns the object to the Pool.
Best Use cases for Pool
  • Plain buffer management
  • Non-composite objects lifecycle management
Not to Use If
  • Objects that dynamically allocate resources (buffer, sockets)
  • Objects that are processed asynchronously.
References

Neovim, Vim and Go Setup on Mac

  • Installing neovim

       pip2 install --user neovim
       pip3 install --user neovim
    
  • If you need Homebrew’s Python 2.7 run
    brew install python@2

  • You can install Python packages with

    pip3 install <package>
    

    They will install into the site-package directory
    /usr/local/lib/python3.7/site-packages

  • Path of neovim rc

– So far the most complete Go-vim setup:

Written with StackEdit.