Go

Good Read:

SETUP

brew install go
mkdir $HOME/go && cd $HOME/go && mkdir bin pkg src && cd -
echo "export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
" >> ~/.zshrc
source ~/.zshrc  

Build

Ref:

Go module 410 Gone

$ export GO111MODULE=on
$ export GOPROXY=direct
$ export GOSUMDB=off
$ go get -v -u github.com/alessiosavi/GoGPUtils@v0.0.9

Use -ldflag to override main variable

var version string
var date string

func main() {
    fmt.Printf("version=%s, date=%s", version, date)
}
go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~10,4%-%date:~4,2%-%date:~7,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"

Goos/Goarc list

go tool dist list
$GOOS $GOARCH
darwin amd64
linux amd64
windows amd64

Test

Test failed if test coverage below 80%

func TestMain(m *testing.M) {
    // call flag.Parse() here if TestMain uses flags
    rc := m.Run()

    // rc 0 means we've passed,
    // and CoverMode will be non empty if run with -cover
    if rc == 0 && testing.CoverMode() != "" {
        c := testing.Coverage()
        if c < 0.8 {
            fmt.Println("Tests passed but coverage failed at", c)
            rc = -1
        }
    }
    os.Exit(rc)
}

Cover mode https://blog.golang.org/cover

go test -covermode=set # did each statement run? 
go test -covermode=count # how many times did each statement run?
go test -covermode=atomic # like count, but counts precisely in parallel programs

Get coverage rate (source)

go test -covermode=count -coverprofile=coverage.out ./internal/... | grep coverage | cut -d ' ' -f 2 | sed 's/%//g'

Mock

Mocking using GoMock

# install gomock
go get github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen

mockgen -source=flow/kafka_admin.go -destination=flow/mock_kafka_admin.go -package=flow

Benchmarking

Interpreting result

BenchmarkCountParallel-2   	   10000	    163742 ns/op	       0 B/op	       0 allocs/op
  • 2: num procs
  • 1000: number of interation run
  • 163742 ns/op: average time each function call takes to complete
  • 0 B/op: memory block (present because of the -benchmem flag)

Interfaces

Reference:

Implements of io.Reader

strings.NewReader("some string\n")
bytes.NewReader([]byte{})

Implements of io.Writer

buff := bytes.Buffer{}
buff.WriteString("some string")

Reader to ReaderClose

ioutil.NopCloser(reader)

PROFILING/OPTIMIZATION

Ref:

expvar package

import _ "expvar"

// URL Path:
// /debug/vars

pprof package

import _ "net/http/pprof"

// URL Path
// /debug/pprof/
// /debug/pprof/cmdline
// /debug/pprof/profile
// /debug/pprof/symbol
// /debug/pprof/trace
// /debug/pprof/goroutine
// /debug/pprof/threadcreate
// /debug/pprof/heap
// /debug/pprof/block

Context

  • WithValue: the process may need this value
  • WithCancel: the process can be cancelled
  • WithDeadline: the process can be expired
  • WithTimeout: same with WithDeadline

Reflection

Print function of packages

subPackage := "app/controller"

set := token.NewFileSet()
packs, err := parser.ParseDir(set, subPackage, nil, 0)
if err != nil {
	fmt.Println("Failed to parse package:", err)
	os.Exit(1)
}

// funcs := []*ast.FuncDecl{}
for _, pack := range packs {
	for _, f := range pack.Files {
		for _, d := range f.Decls {
			if fn, isFn := d.(*ast.FuncDecl); isFn {
				// funcs = append(funcs, fn)
				fmt.Println(fn.Name)

			}
		}
	}
}

Assign pointer to other with reflection

n := 42
p := &n

x := new(int)
// set the value to *x, but x must be initialized
reflect.ValueOf(x).Elem().Set(reflect.ValueOf(p).Elem())
fmt.Println("*x:", *x)

var y *int
// to set the value of y directly, requires y be addressable
reflect.ValueOf(&y).Elem().Set(reflect.ValueOf(p))
fmt.Println("*y:", *y)

Get Package Name

// If the type was predeclared (string, error) or not defined (*T, struct{},
// []int, or A where A is an alias for a non-defined type), the package path
// will be the empty string.
func packageName(v interface{}) string {
	val := reflect.ValueOf(v)
	if val.Kind() == reflect.Ptr {
		return val.Elem().Type().PkgPath()
	}
	return val.Type().PkgPath()
}

AST

ref:

Print the ast

ast.Print(fset, v)

Inspect

func inspect(n ast.Node) {
	ast.Inspect(n, func(n ast.Node) bool {
		var s string
		switch x := n.(type) {
		case *ast.BasicLit:
			s = x.Value
		case *ast.Ident:
			s = x.Name
		}
		if s != "" {
			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
		}
		return true
	})
}

To String

func toString(v interface{}) string {
	var buf bytes.Buffer
	err := printer.Fprint(&buf, fset, v)
	if err != nil {
		log.Fatal(err)
	}
	return buf.String()
}