1009  字
  5  分钟 
  Go Cheat Sheet 
 编译时加入版本信息
package main
import (    "fmt"    "os")var (    gitHash   string    buildTime string    goVersion string)func main() {    args := os.Args    if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {        fmt.Printf("Git Commit Hash: %s \n", gitHash)        fmt.Printf("Build TimeStamp: %s \n", buildTime)        fmt.Printf("GoLang Version: %s \n", goVersion)        return    }}go build -ldflags "-X 'main.goVersion=$(go version)' -X 'main.gitHash=$(git show -s --format=%H)' -X 'main.buildTime=$(git show -s --format=%cd)'"embed 相对路径
package res
import (  _ "embed")
//go:embed ../.temp/temp.txtvar tempFile stringdefer
顺序
func main() {    defer fmt.Println(1)    defer fmt.Println(2)    defer fmt.Println(3)
    fmt.Println("main")}main321闭包
func main() {    a := 1    b := 2
    defer fmt.Println(a + b)
    a = 2}3func main() {    a := 1    b := 2
    defer func() {        fmt.Println(a + b)    }()
    a = 2}4返回
func t1() int {    a := 1    defer func() {        a++    }()    return a}1func t2() (a int) {    defer func() {        a++    }()    return 1}2defer 中的 a 来自外部(需要返回的),所以内部自加会影响返回值。
func t4() (a int) {  defer func(a int) {    a++  }(a)  return 2}2defer 中的 a 是外部的复制。
os.Exit
func main() {    defer fmt.Println("1")    fmt.Println("main")    os.Exit(0)}main程序退出不会执行 defer
coroutine
func main() {    GoA()    time.Sleep(1 * time.Second)    fmt.Println("main")}
func GoA() {    defer (func(){        if err := recover(); err != nil {            fmt.Println("panic:" + fmt.Sprintf("%s", err))        }    })()
    go GoB()}
func GoB() {    panic("error")}GoA 无法捕获 GoB 的错误。
for idx & range 性能对比
测试
package main
import "testing"
type Item struct {  id  int  val [4096]byte}
func BenchmarkForStruct(b *testing.B) {  var items [1024]Item  for i := 0; i < b.N; i++ {    length := len(items)    var tmp int    for k := 0; k < length; k++ {      tmp = items[k].id    }    _ = tmp  }}
func BenchmarkRangeIndexStruct(b *testing.B) {  var items [1024]Item  for i := 0; i < b.N; i++ {    var tmp int    for k := range items {      tmp = items[k].id    }    _ = tmp  }}
func BenchmarkRangeStruct(b *testing.B) {  var items [1024]Item  for i := 0; i < b.N; i++ {    var tmp int    for _, item := range items {      tmp = item.id    }    _ = tmp  }}结果
➜  go_test go test -benchmem -run=^$ -bench ^Benchmark range_test.gogoos: darwingoarch: arm64BenchmarkForStruct-8             3486474               330.4 ns/op             0 B/op          0 allocs/opBenchmarkRangeIndexStruct-8      3637329               329.9 ns/op             0 B/op          0 allocs/opBenchmarkRangeStruct-8              6810            164832 ns/op               0 B/op          0 allocs/opPASSok      command-line-arguments  4.279s差距大概50倍。
原因是for range的k,v中的v是复制的,需要申请内存(除非值为指针)。
for range尽量只使用下标,不使用值。
any 传入 []any或map[string]any
v := reflect.ValueOf(i)switch v.Kind() {case reflect.Slice:  items := make([]any, v.Len())  for i := 0; i < v.Len(); i++ {    items[i] = v.Index(i).Interface()  }case reflect.Map:  items := make(map[string]any)  for _, key := range v.MapKeys() {    items[key.String()] = v.MapIndex(key).Interface()  }}string
for idx & for range
a := "1万🔖"for i := 0; i < len(a); i++ {  println(i, a[i])}println()for i := range a {  fmt.Println(i, a[i])}println()for i, v := range a {  fmt.Println(i, v)}0 491 2282 1843 1354 2405 1596 1487 150
0 491 2284 240
0 491 199754 128278拼接
多次拼接使用strings.Builder
func builderConcat(strs... string) string {  var builder strings.Builder  for _, str := range strs {    builder.Grow(len(str))  }
  for _, str := range strs {    builder.WriteString(str)  }  return builder.String()}error
==
err1 := errors.New("error1")err2 := errors.New("error1")err1 == err2 // falsereflect.DeepEqual(err1, err2) // trueerrors.Is(err1, err2) // false即使error内部str相同,也不==
可以使用reflect.DeepEqual,但是linter不推荐
time
ticker
package main
import (  "time")
func main() {  ti := time.NewTicker(time.Second * 2)  times := 0  for range ti.C {    times++    if times % 2 == 0 {      println("tick")      continue    }    println(time.Now().Format("2006-01-02 15:04:05"))  }}输出:
2022-08-08 18:36:00tick2022-08-08 18:36:04tick2022-08-08 18:36:08tick2022-08-08 18:36:12tick2022-08-08 18:36:16ticker中continue不会直接进入下一个循环,而是会等待ticker到达预定时间才运行
json
interface{}
var temp interface{}userStr := `{"name":"zhangsan","age":18}`err := json.Unmarshal([]byte(userStr), &temp)if err != nil {  println(err.Error())} else {  fmt.Printf("%#v\n", temp)}// 输出:// map[string]interface {}{"age":18, "name":"zhangsan"}interface{} -> map[string]interface{}
flag
bool
b := flag.Bool("b", false, "bool flag")flag.Parse()println(*b)go run . --b # truego run . # false:=
a := 0if a == 0 {  a, _:= strconv.Atoi("1")  fmt.Printf("%#v\n", a) // 1}fmt.Printf("%#v\n", a) // 0:=表示为一个新对象,if外部a对象被覆盖了,只在if作用域内a为1
单、双、反引号
fmt.Printf("%#v\n", '\v') // 11单引号,表示byte类型或rune类型,对应 uint8和int32类型,默认是 rune 类型。
``用来强调数据是raw data;而rune用来表示Unicode的code point。
nil 详解
格式化输出(前置0)。
package main
import "fmt"
func main() {    var num1 int = 5
    // 使用 %0Nd,其中 N 是你想要的宽度    fmt.Printf("%05d\n", num1)}在这个例子中,%05d 会打印一个宽度为 5 的整数,如果整数的长度小于 5,那么它会在前面添加 0 以达到 5 的宽度。
 Go Cheat Sheet 
  https://blog.lpkt.cn/posts/go-cheat-sheet/     
  