go module
Go module is released in go 1.12 to help package control.
Module can be found at https://godoc.org/
- At the root of go module, we have a
go.mod
file.- can be generated via
go mod init
- can be generated via
- any sub-dir (packages) will be considered part of the module
go list -m all # print current module dependency
go get # update a dependency
go mod tidy # remove unused dependency
environment variable
GOROOT - go sdk install dir
GOPATH - go workspace dir
GOBIN - binary install dir
command
go run # build & run
--race # detect data race
go generate # generate go code
go build -ldflags="-s -w" hello.go # remove symbol table and debugging info
go install # install to $GOBIN
go get # download package to src
go fmt # format files
dlv debug --headless --listen localhost:2345 --api-version 2 # debug
--build-flags '-race'
plugin
go build -buildmode=plugin -o test.so <src>
p, err := plugin.Open("test.so") // load so
v, err := p.Lookup("V") // lookup symbol
cgo
//export Function
: generate c header
go:linkname mallocgc runtime.mallocgc
https://golang.org/cmd/cgo/
go language
The program entry point is:
package main
func main() {}
The package
must be the first line
panic()
// return the argument passed to panic
recover()
// each source file can have init() functions
// init() is evaluated after imported packages
init()
_
is used as a dummy variable- can suppress unused import and unused variable
import _ "net/http/pprof"
for side effect
- A
defer
statement defers the execution of a function until the surrounding function returns- ie: the surrounding
func
defer
runs in LIFO
- ie: the surrounding
- make only works for map, slice, and channel
- they hold reference to the underlying data structure, so changes are visible
- map element is not addressable -> no pointer to them
- use pointer when in doubt
:=
will always shadow outer variableswitch, select
has a default break after each casebreak
: exit fromfor, switch, select
continue
: continue fromfor
fallthrough
: transfer control to next case, must be last statement in current case
fmt
has special handling for some interface- https://godoc.org/fmt
.error
loop
for init; condition; post {}
for condition {}
for {}
break
breaks from innermostfor, switch, select
- loop variable is reused in go
- if used within the goroutine, the value will change.
- iter
struct vs interface
type Android struct {
Person // anonymous field -> is-a relation
// called embedding in go, can also be used on interface
Model string // -> has-a relation
}
func (a *Android) () {
// define function for struct
// there is also func (a Android) () {}
}
// interface only list functions which are necessary to fullfill the interface
// interface can held a struct or a pointer to a struct
// so, a pointer to interface is not necessary
// https://stackoverflow.com/questions/44370277/type-is-pointer-to-interface-not-interface-confusion
type Shape interface {
area() float64
}
interface{}
= anystruct{}
= none- Go Data Structures: Interfaces
- interface stores type info (T) and concrete data (V) as pointer
- similar to vtable in c++ -> Itab in go?
- table computed for concrete type and interface
- at runtime, the two tables are bind together
- when a library is compiled, it does not know if it will be used in a specific interface?
- interface stores type info (T) and concrete data (V) as pointer
- when comparing interface, T and V needs to match
- data is converted to interface for comparison
- nil -> T = nil and V = nil
- for nil pointer -> T != nil and V = nil
// a syntax sugar that ensures a closure function also satifies its interface
type readerFunc func(p []byte) (n int, err error)
func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) }
array vs slice
- array are values, so it is always copied
- size of array is part of its type
- slice hold a reference to its content
- internal changes are visible through copy
- if slice is reallocated, the reference is changed
func main() {
slice:=[]string{"a","a"}
func(slice []string) {
slice[0] = "b"
slice[1] = "b"
slice = append(slice, "a") // reallocate
fmt.Print(slice) // bba
}(slice)
fmt.Print(cap(slice))
fmt.Print(len(slice))
fmt.Print(slice) // bb
}
func main() {
sliceA := make([]byte, 10)
sliceC := sliceA[1:]
sliceD := sliceA[2:]
// sliceC and sliceD share the one backing array
// we can check by the following
fmt.Println(&sliceC[cap(sliceC)-1] == &sliceD[cap(sliceD)-1]) // true
}
error
error
is a interfacefmt.Errorf
returnserror
%w
wraps another error in format
- since go 1.13, error can be chained
- error.Unwrap() return the underlying err
error.Is
anderror.As
will also check underlying err
go routine / channel
go func()
- limit the amount of go routine
- channel could block if there is no receiver
close(chan)
will retain its remaining values- write to a closed chan will panic
range
will wait on channel forever if not closedselect
can used to wait on multiple channels- and to avoid waiting with
default
- receive from a closed channel yields zero value
- a nil channel is never ready for comm
- select give no priority over order of case
- and to avoid waiting with
sync
Pool
- memory pool for temporary object
- since go 1.13, a doubly linked list with used/free section
- New / Put / Get
- New create new object for initial Get
- object in pool might be GCed at any time
- Mutex
- WaitGroup
- Cond
- Context
type
- there is only type assertion and type conversion
- assertion only works on interface to get its actual underlying type.
- type identity
- Named type:
- int / string / etc + type declaration
- type name must match to be identical
- Unnamed type:
- array / slice / map
- they are only a description of structure
- match as long as underlying type match
- Alias:
type myInt = int
- Named type:
// type assertion
tmp, ok = value.(typeName)
// type switch
switch str := value.(type) {
case typeName:
}
reflect
https://blog.golang.org/laws-of-reflection
MakeFunc
ValueOf
DeepEqual
three dots
- last parameter of variadic function parameter
...T
- unpack arguments to variadic function
s...
- array literal
[...]string{"Moe", "Larry"}
- wildcard symbol in go command
test and benchmark
https://blog.golang.org/pprof https://golang.org/doc/diagnostics.html
go test -run=xxx # run all test matching xxx
go test -bench=. # run all tests + benchmarks
- benchmark is run for a minimum of 1s.
-benchtime
- benchmark is run until stable
- changing runtime is not acceptable
- compiler might eliminate function
- always retrieve result to a package level variable
import
- internal:
-
importable only by code in the directory tree rooted at the parent of “internal”
-
- vendor:
go mod vendor
- vendor with GOPATH?
- packages are found in all
vendor
folder
- packages are found in all
- vendor with module
- packages are found in the
vendor
at module’s root -mod=vendor
,-mod=mod
- since go 1.14, vendor is automatically used
- packages are found in the
- useful for private package import?
- limit import url
package gin // import "github.com/gin-gonic/gin"
workspace - legacy
- a go project is kept in one workspace
- $GOPATH should point to this workspace
- a workspace will include following directory
- src: packages sources
- bin: compiled binary will be installed here
- pkg: compiled static lib here (will be platform & arch specific)
- src can include many directory
- each directory become its own package
- one of which is user’s project, others can be from
go get
- package version need to be manually controlled
- all files in the same package must use the same package name.
- one of which is user’s project, others can be from
- each directory become its own package
runtime.schedule()
- P - processor
- limited by the number of logical processors (GOMAXPROCS)
- when wake up a P, a M is created
- M - os thread
- M must have a associated P to execute
- M > P is possible if M is blocked
- M will run G until blocked
-
G - go routine
- When G is spawned, it is pushed onto a runnable queue
- if P has a empty queue, it can steal from other P
- if M makes a blocking syscall
- pessimistic, detach P from M
- optimistic, sysmon waits until M spends too much time
- (some syscalls return quickly)
- P can be stolen to run other M
- if M is making a async syscall
- M can block just as a G
- the result can be polled on next schedule
runtime.schedule()
go tool trace
- work-share vs work-steal
- local and global runnable queue
- spinning thread - so that M do not get preemption
protobuf
- install protoc
- protoc for golang is a plugin:
go install google.golang.org/protobuf/cmd/protoc-gen-go
- protoc
proto_path
- if message are defined in several files, all source need to be included in this directory
go_out
-> all generated file will be relative to this diroption go_package "full path";
generated into this path relative to go_out- –go_out=$GOPATH: so that pb file becomes its own package for import
go_opt=paths=source_relative
-> generated files are placed in output dir based on source’s relative position vs proto_path- ignores go_package setting
todo
https://go101.org/article/101.html https://github.com/golang/go/wiki/CodeReviewComments https://blog.golang.org/generics-next-step
package
https://golang.org/pkg/ https://godoc.org/-/subrepo
reader
- note that reader stall on empty stdin?
io.ioutil bytes.Buffer strings.Builder bufio
gob wire gin tomb
string
A string holds arbitrary bytes. A string literal, absent byte-level escapes, always holds valid UTF-8 sequences. Those sequences represent Unicode code points, called runes. No guarantee is made in Go that characters in strings are normalized.