Go programming language Stdlib Proverbs Effective Go rc
- HOWTO Install by Brew
brew install goHomebrew Go package. - DOC Package name convention are given lower case, single-word names; there should be no need for underscores or mixedCaps. Naming convention style Effective Go Package names Code Review Package names Go Blog Package names 4282605948
- DOC Interface name convention use an -er suffix: Reader, Writer, Formatter, CloseNotifier etc. Naming convention style 2453223740
- HOWTO Environment
go env - DOC Book "The Go Programming Language" Alan A. A. Donovan, Brian W. Kernighan *
- HOWTO Install package
go get -v ./...Get with all dependencies (exclude test dependencies). - HOWTO Install package with test dependencies
go get -v -t ./...Get test dependencies. - HOWTO Update package
go get -u your.tld/path/to/pkg - HOWTO Package dependencies list
go list -f '{{ .Deps }}' your.tld/path/to/pkgList package dependencies - HOWTO Install package
go install your.tld/path/to/pkg - HOWTO List packages
go list ./...List installed packages. 557989519 - HOWTO Testing
go test -v -race -count=1 ./...Run test suite 2319142434 2570645731 - HOWTO Testing of remote package
go test your.tld/path/to/pkg - HOWTO Testing without cache
go test -count=1Testing with cache disabled. 4126800382 - HOWTO VER2 Test benchmark
go test -race -count=1 -bench=. -benchmem ./...Run benchmark. - HOWTO Test coverage
go test -cover ./...2445429477 - HOWTO
go test -race ./...Test races/race condition/with race detector. 1720623323 - HOWTO Table test generator
- HOWTO godef finds function definition
go get github.com/rogpeppe/godef && godef -f path/to/file.go 'yourpkgnm.YourFnNm'Find function definition by package and function name. - HOWTO Run
go run ./... - HOWTO Get build ID
go tool buildid path/to/your/fileDisplay or update the build ID stored in a Go package or binary. - HOWTO Build
CGO_ENABLED=0 go build ./...4169212427 318174330 - HOWTO Build custom name
go build -o path/to/your/executableBuild with custom executable name and custom output directory. - HOWTO Build without cache
go build -a path/to/your/packageBuild cache invalidation. Invalidate cache. Recompile. - HOWTO Runtime Gosched
runtime.Gosched()Yields the processor, allowing other goroutines to run. It necessary for cooperative scheduler (кооперативного планировщика) until Go 1.13 and unnecessary for preemptive scheduler (вытесняющего планировщика) starts Go 1.14. 3989277831 - HOWTO Runtime GC disable
GOGC=off269738468 - HOWTO Debug FreeOSMemory
debug.FreeOSMemory()Forces a garbage collection followed by an attempt to return as much memory to the operating system as possible. - HOWTO Reduce binary size while build
go build --ldflags "-s -w" path/to/packageMinimize binary size. - HOWTO Reduce binary size while run
go run --ldflags "-s -w" path/to/packageMinimize binary size. - HOWTO Compile time variables while build
go build -ldflags "-X path/to/package.foo=$(git describe --abbrev=0 --tags) -X path/to/package.Bar=$(git rev-parse --short HEAD) -X path/to/package.baz=$(git rev-parse HEAD) -X path/to/package.qux=$(date --utc +%s) -X path/to/package.xyz=$(date --utc +%Y%m%dT%H%M%SZ)" main.goSet some string variable on compile time (for example your some "version"). - HOWTO Compile time variables while run
go run -ldflags "-X path/to/package.foo=123 -X path/to/package.Bar=xyz" ./...Set some string variable on compile time (for example your some "version"). - HOWTO Cross compilation
env GOARCH=arm64 go build - HOWTO Code review: 80 characters or not? Code review: N characters line length convention style.
- HOWTO Code review: Initialism convention
Id->IDUrl->URLXml->XMLand so on Code review abbreviation style. - HOWTO Code review: The named return is good but the naked is bad Convention style. Bare return is bad. 1 2 3
- HOWTO Type conversion
var i int = 42; f float64 = float(i); i := (*int)(nil)Example. - HOWTO Type assertion
var x interface{} = 42; i := x.(int)Example. - DOC Generic type Intro generics since 1.18. When generics. Example[].
- HOWTO Dave Cheney: "accept interfaces, return structs" 991876724 Jack Lindamood: "A great rule of thumb for Go is accept interfaces, return structs." Cite.
- HOWTO Non-nil interface type and nil interface value
if i, ok := value.source.(fmt.Stringer); ok {; if i == nil || (reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil()) {; return "This is real nil or nil value and non nil type."; }; } - HOWTO Print Formatter
type Formatter interface {; Format(f State, c rune); }99610387 - HOWTO Print Structured logging Printing. Logging. Structured logging blog article
- HOWTO Print Go-cmp compare values
cmp.Equal(your_val1, your_val2)andcmp.Diff(your_val1, your_val2)Printing. Logging. Check equality or difference.ignore := []cmp.Option{cmpopts.IgnoreFields(yourpkg.YourType{}, "YourFld1", "YourFld1")}; if !cmp.Equal(got, want, ignore...) { t.Errorf("\nyour diff:\n%s\ntest: %s", cmp.Diff(want, got, ignore...), "path/to/your_test.go:42") }GitLab uses go-cmp too. Dave Cheney uses cmp too. Testing. Debuging. Compare difference. Pretty print. - HOWTO Print Proto equal
proto.Equal(your_proto1, your_proto2)Printing. Logging. Check equality. Testing. Debugging. DeepEqual - HOWTO Print Proto diff
cmp.Diff(your_proto1, your_proto2, protocmp.Transform())Printing. Logging. Check difference. Testing. Debugging. DeepEqual - HOWTO Print Error diff
cmp.Diff(your_error1, your_error2, cmpopts.EquateErrors())Printing. Logging. Check difference. Testing. Debugging. - HOWTO Error wrap format join
errors.Join(fmt.Errorf("your error: %w", errors.New("foo")), errors.New("bar"))Wrapping. Formatting. Joining. 1238582052 2031092561 2122683529 - HOWTO Error unwrap and compare
func equal(err, err2 error) bool { if err == err2 { return true }; if err := errors.Unwrap(err); err != nil { if ok := equal(err, err2); ok { return true } }; if v, ok := err.(interface{ Unwrap() []error }); ok { for _, err := range v.Unwrap() { if ok := equal(err, err2); ok { return true } } }; return false }The exampleequalfn compares the wrapped errors recursively. 1121809002. - DOC Sentinel is a
sentinel errorWorking with Errors in Go 1.13 Dave Cheney, Sentinel error Error Inspection Draft Design 2018-08-27 Damien Neil - DOC Sentinel io.EOF End of input. Common error. 564276647
- DOC Sentinel os.ErrInvalid fs.ErrInvalid Invalid argument. Common error. 564276647
- DOC Sentinel os.ErrPermission fs.ErrPermission Permission denied. Common error. 564276647
- DOC Sentinel os.ErrExist fs.ErrExist File already exists. Common error. 564276647
- DOC Sentinel os.ErrNotExist fs.ErrNotExist File does not exist. Common error. 564276647
- DOC Sentinel os.ErrClosed fs.ErrClosed File already closed. Common error. 564276647
- DOC Sentinel os.ErrNoDeadline File type does not support deadline. Common error. 564276647
- DOC Sentinel os.ErrDeadlineExceeded I/O timeout. Common error. 564276647
- DOC Sentinel sql.ErrNoRows No rows in result set. Common error. 564276647
- DOC Sentinel sql.ErrNoRows No rows in result set. Common error. 564276647
- DOC Sentinel fs.PathError 1595088486
- DOC Sentinel fs.PathError
if e, ok := err.(*fs.PathError); ok { e.Timeout() }or url.Errorif e, ok := err.(*url.Error); ok { e.Timeout() }or in generalif e, ok := err.(interface{ Timeout() bool }); ok { e.Timeout() }1595088486 - DOC Sentinel url.InvalidHostError is a
string error. - HOWTO Explicit argument indexes of formatter
fmt.Sprintf("%[2]d %[1]d", 11, 22)Position argument. 3426125172 - HOWTO Create dir or append file
if _, err := os.Stat("your.f"); errors.Is(err, os.ErrNotExist) { _ = os.MkdirAll(filepath.Dir("your.f"), os.ModePerm) }; f, _ := os.OpenFile("your.f", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); defer f.Close(); _, _ = f.Write([]byte("Hello, World!"))Create or update/append file after create directory if not exist. 2502395997 3382294025 - HOWTO Create temp file VER2
dirNm := filepath.Join(os.TempDir(), "your_dir"); _ = os.MkdirAll(dirNm, os.ModePerm); fileNm := filepath.Join(dirNm, "file_nm"+itoa.Uitoa(rand.Uint64())); f, _ := os.Create(fileNm); defer f.Close(); _, _ = f.Write([]byte("foo bar"))Create temporary file. - HOWTO Create temp file VER1
f, _ := os.CreateTemp(filepath.Join(os.TempDir(), "your_dir"), "your_prefix_"); defer f.Close(); _, _ = f.Write([]byte("foo"))Create temporary file. - HOWTO Create temp dir VER2
_ = os.MkdirAll(filepath.Join(os.TempDir(), "your_dir"), os.ModePerm)Create temporary directory. Functionos.MkdirTempjust like DEPRECATEDioutil.TempDir. - HOWTO Create temp dir VER1
d, _ := os.MkdirTemp("", "your_prefix_"); defer os.RemoveAll(d)Create temporary directory. - HOWTO Read all bytes
var bbytes.Buffer; io.Copy(&b r); fmt.Println("%s", b.String())Functionio.Copyjust like DEPRECATEDioutil.ReadAll. - HOWTO
paths, err := filepath.Glob(pattern)Globbing pattern sets of filenames with wildcard characters. - HOWTO Flag Kong is a multi command command-line parser an alternative to using flag.FlagSet PROS: Passthrough argument. 3264233233 NOTE: Console. Terminal.
- HOWTO VER1 Flag Flag set command-line parser allow multi command In case you can't use, for example, Kong. Console. Terminal.
HOWTO Hello, World!
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}$ go run ./...
Hello, World!cat go.mod
module yourpkg
require "your.tld/you/yourpkg" v0.0.0
replace "your.tld/you/yourpkg" v0.0.0 => "./"
cat yourpkg.go
package yourpkg
var hello string
func YourInit() { hello = "Hello" }
type T string
func New() T { return T(hello) }
func (x *T) YourFn(s string) { *x = T(string(*x)[:len(hello)] + " " + s) }
func (x *T) YourReset() { *x = T(string(*x)[:len(hello)]) }cat your_test.go
package yourpkg_test
import (
"fmt"
"path/filepath"
"runtime"
"testing"
"your.tld/you/yourpkg"
)
var tests = []struct {
name string
line string
in string
out string
}{
{name: "test Alice", in: "Alice", out: "Hello Alice", line: line()},
{name: "test Bob", in: "Bob", out: "Hello Bob", line: line()},
}
func line() string {
if _, file, line, ok := runtime.Caller(1); ok {
return fmt.Sprintf("%s:%d", filepath.Base(file), line)
}
return "it was not possible to recover file and line number information about function invocations"
}
func TestYourFn(t *testing.T) {
t.Parallel()
yourpkg.YourInit()
for _, tt := range tests {
tt := tt
t.Run(tt.line+"/"+tt.name, func(t *testing.T) {
t.Parallel()
in := yourpkg.New()
in.YourFn(tt.in)
if string(in) != tt.out {
t.Errorf("\nwant: %s\n got: %s", tt.out, in)
}
})
}
}
func BenchmarkYourFn(b *testing.B) {
yourpkg.YourInit()
b.ResetTimer()
b.ReportAllocs()
for _, tt := range tests {
b.Run(tt.name, func(b *testing.B) {
in := yourpkg.New()
for i := 0; i < b.N; i++ {
in.YourFn(tt.in)
}
b.StopTimer()
in.YourReset()
b.StartTimer()
})
}
}go test -race -count=1 -bench=. -benchmem ./...
HOWTO Test: fstest: Mocking relative path of file system 3825108315 1746671570 2434259655 1056894504
package main
import "testing/fstest"
func main() {
testFS := fstest.MapFS{
"relative/path/to.file": {
Data: []byte("Hello, world!"),
},
}
p, err := testFS.ReadFile("relative/path/to.file")
if err != nil {
panic(err)
}
println(string(p) == "Hello, world!")
}- https://go.dev/doc/effective_go#package-names>
- https://go.dev/blog/package-names#bad-package-names
- https://github.com/golang/go/wiki/CodeReviewComments#package-names
Bad package name examples: util, common and misc
- Wall or Civil * arguments for
time.Timetype and againsttime.Datetype - Monotonic or Absolute *
fmt.Println(time.Duration(float64(42*time.Second) * 1.23))
for i := 1; i < 100500; i++ {
d := time.Duration(float64(42*time.Second) * (1 + math.Log(float64(i))))
if d > 3*time.Minute {
d = 3 * time.Minute
}
time.Sleep(d)
}
timer := time.NewTimer(time.Second)
timer.Stop()
select {
case <-timer.C:
default:
}
timer.Reset(d)
HOWTO String convertor to CamelCase
import "google.golang.org/protobuf/internal/strs"
strs.GoCamelCase("text_2") // Text_2
strs.GoCamelCase("text2") // Text2
regexp.MustCompile("^[a-z]+$").MatchString("foo")
regexp.MustCompile("(?m)^[a-z]*$\n[a-z]*").MatchString("foo\nxyz")
regexp.MustCompile("(.{3})").ReplaceAll([]byte("foo3"), []byte("${1}12"))
- https://go.dev/ref/spec#Slice_expressions
- https://docs.google.com/document/d/1GKKdiGYAghXRxC2BFrSEbHBZZgAGKQ-yXK-hRKBo0Kk/pub
For examle a[low:high:max] or a[0:0:0] or a[:0:0]
- https://go.dev/wiki/SliceTricks#copy
- https://pkg.go.dev/builtin#copy
- https://pkg.go.dev/builtin#append
- DEPRECATED https://github.com/golang/go/wiki/SliceTricks#copy
b := append(a[:0:0], a...)is the same asb = append([]T(nil), a...)b := make([]T, len(a))and thencopy(b, a)b := append(make([]T, 0, len(a)), a...)
bytes.Compare returns 0 if a == b, -1 if a < b, and +1 if a > b
bytes.Compare([]byte{1,2}, []byte{3,4})
a1, a2 := [2]byte{1, 2}, [2]byte{3, 4}
fmt.Println(bytes.Compare(a1[:], a2[:]))
https://pkg.go.dev/testing/fstest
package main
import "github.com/jinzhu/copier"
type T1 struct {
Name string
}
type T2 struct {
Name string
Age int
}
func main() {
t1 := T1{Name: "John Doe"}
t2 := T2{Age: 42}
if err := copier.Copy(&t2, &t1); err != nil {
panic(err)
}
}- context.Context
- net.Context Is a former beta version.
HOWTO VER2 Flag Flag set Multi command and Multi flag.FlagSet in case you can't use, for example, Kong. Console. Terminal.
package main
import (
"fmt"
"flag"
"os"
)
func main() {
switch os.Args[1] {
case "foo":
set := flag.NewFlagSet("foo", flag.ExitOnError)
bar := set.Bool("bar", false, "")
_ = set.Parse(os.Args[2:])
fmt.Println(*bar)
case "xyz":
set := flag.NewFlagSet("xyz", flag.ExitOnError)
baz := set.Bool("baz", false, "")
_ = set.Parse(os.Args[2:])
fmt.Println(*baz)
}Query string of Uniform Resource Identifier URI encoded in application/x-www-form-urlencoded algorithm is a sorted list of name-value pairs implemented by net/url package encodes the values into URL encoded form sorted by key.
v := url.Values{}
v.Add("3", "xyz"); v.Add("1", "foo"); v.Add("2", "bar")
fmt.Println(v.Encode()) // 1=foo&2=bar&3=xyz
https://go.dev/play/p/gCRFEuO4CkC
DOC JSON marshaling of map fields in sorted order
The Go Stdlib already preserves sorted order of map keys:
The map keys are sorted
HOWTO HTTP multipart/form-data POST of file by local path * 1102513506 1351755388
curl -X POST "https://your.tld/your/path" -H "Content-Type: multipart/form-data" -F "file=@/etc/hostname;filename=your.file;type=*/*" --basic --user your_user:your_password
package main
import (
"bytes"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"path/filepath"
)
func main() {
form := new(bytes.Buffer)
writer := multipart.NewWriter(form)
fw, err := writer.CreateFormFile("file", filepath.Base("your.file"))
if err != nil {
log.Fatal(err)
}
fd, err := os.Open("/etc/hostname")
if err != nil {
log.Fatal(err)
}
defer fd.Close()
_, err = io.Copy(fw, fd)
if err != nil {
log.Fatal(err)
}
writer.Close()
client := &http.Client{}
req, err := http.NewRequest("POST", "https://your.tld/your/path", form)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.SetBasicAuth("your_user", "your_password")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", bodyText)
}