-
go fmt 代码, 让代码更清晰
-
多个if判断可以改成switch
-
使用
chan struct{}
来传递信号 -chan bool
makes it less clear, btwstruct{}
更优化 struct{}不需要占用任何内存空间 -
使用
30 * time.Second
代替time.Duration(30) * time.Second
-
for-select 结构 封装成 函数 ``` func main() { foo() fmt.Println("ending") }
func foo() { for { select { case <-time.After(time.Second): fmt.Println("hello") default: return } } } ```
-
group
const
declarations by type andvar
by logic and/or type -
every blocking or IO function 阻塞程序必须能取消或取超时机制
-
implement
Stringer
interface for integers const values -
check your defer's error
defer func() { err := ocp.Close() if err != nil { rerr = err } }()
-
don't use
checkErr
function which panics or doesos.Exit
-
don't use alias for enums 'cause this breaks type safety
package main type Status = int type Format = int // remove `=` to have type safety const A Status = 1 const B Format = 1 func main() { println(A == B) }
-
省略函数返回参数:
- so prefer this
_ = f()
to thisf()
- so prefer this
-
we've a short form for slice initialization
a := []T{}
-
iterate over array or slice using range loop
- instead of
for i := 3; i < 7; i++ {...}
preferfor _, c := range a[3:7] {...}
- instead of
-
use backquote(`) for multiline strings
- run
go format
on CI and compare diff- this will ensure that everything was generated and commited
- to run Travis-CI with the latest Go use
travis 1
- check if there are mistakes in code formatting
diff -u <(echo -n) <(gofmt -d .)
- best candidate to make something once in a thread-safe way is
sync.Once
- don't use flags, mutexes, channels or atomics
- to block forever use
select{}
, omit channels, waiting for a signal
- do not omit
defer
- 200ns speedup is negligible in most cases
- always close http body aka
defer r.Body.Close()
- unless you need leaked goroutine
- filtering without allocating
b := a[:0] for _, x := range a { if f(x) { b = append(b, x) } }
-
time.Time
has pointer fieldtime.Location
and this is bad for go GC- it's relevant only for big number of
time.Time
, use timestamp instead
- it's relevant only for big number of
- prefer
regexp.MustCompile
instead ofregexp.Compile
- in most cases your regex is immutable, so init it in
func init
- in most cases your regex is immutable, so init it in
- do not overuse
fmt.Sprintf
in your hot path. It is costly due to maintaining the buffer pool and dynamic dispatches for interfaces.- if you are doing
fmt.Sprintf("%s%s", var1, var2)
, consider simple string concatenation. - if you are doing
fmt.Sprintf("%x", var)
, consider usinghex.EncodeToString
orstrconv.FormatInt(var, 16)
- if you are doing
- always discard body e.g.
io.Copy(ioutil.Discard, resp.Body)
if you don't use it- HTTP client's Transport will not reuse connections unless the body is read to completion and closed
res, _ := client.Do(req) io.Copy(ioutil.Discard, res.Body) defer res.Body.Close()
- don't use defer in a loop or you'll get a small memory leak
- 'cause defers will grow your stack without the reason
- don't forget to stop ticker, unless you need leaked channel
ticker := time.NewTicker(1 * time.Second) defer ticker.Stop()
- strip your binaries with this command
go build -ldflags="-s -w" ...
- easy way to split test into different builds
- use
// +build integration
and run them withgo test -v --tags integration .
- use
-
go test -short
allows to reduce set of tests to be runnedfunc TestSomething(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode.") } }
- skip test deppending on architecture
if runtime.GOARM == "arm" { t.Skip("this doesn't work under ARM") }
- prefer
package_test
name for tests, rather thanpackage
- for fast benchmark comparison we've a
benchcmp
tool - track your allocations with
testing.AllocsPerRun
- quick replace
gofmt -w -l -r "panic(err) -> log.Error(err)" .
-
go list
allows to find all direct and transitive dependenciesgo list -f '{{ .Imports }}' package
go list -f '{{ .Deps }}' package
- dump goroutines https://stackoverflow.com/a/27398062/433041
go func() { sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGQUIT) buf := make([]byte, 1<<20) for { <-sigs stacklen := runtime.Stack(buf, true) log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen]) } }()
- check interface implementation during compilation
var _ io.Reader = (*MyFastReader)(nil)
- if a param of len is nil then it's zero
- anonymous structs are cool
var hits struct { sync.Mutex n int } hits.Lock() hits.n++ hits.Unlock()
-
httputil.DumpRequest
is very useful thing, don't create your own - to get call stack we've
runtime.Caller
https://golang.org/pkg/runtime/#Caller