https://github.com/teivah/100-go-mistakes#table-of-contents

nil Map

map记得要make初始化, slice可以不用初始化!

  1. func main() {
  2. var course map[string]string
  3. course["name"] = "go体系课"
  4. }

结构体空指针

空结构体和结构体空指针可不一样

  1. type Course struct {
  2. Name string
  3. Desc string
  4. }
  5. func (c *Course) String() float64 {
  6. return c.Name + c.Desc
  7. }
  8. func main() {
  9. var c *Course
  10. fmt.Println(c.String())
  11. }

使用对循环迭代器变量的引用 - 大坑!

在 Go 中,循环迭代器变量是一个单一的变量,在每个循环迭代中取不同的值。这如果使用不当,可能会导致非预期的行为。

  1. func main() {
  2. var out []*int
  3. for i := 0; i < 3; i++ {
  4. out = append(out, &i)
  5. }
  6. fmt.Println("Values:", *out[0], *out[1], *out[2])
  7. fmt.Println("Addresses:", out[0], out[1], out[2])
  8. }

解决办法

  1. func main() {
  2. var out []*int
  3. for i := 0; i < 3; i++ {
  4. tmpi := i
  5. out = append(out, &tmpi)
  6. }
  7. fmt.Println("Values:", *out[0], *out[1], *out[2])
  8. fmt.Println("Addresses:", out[0], out[1], out[2])
  9. }

原因是:在每次迭代中,我们将 i 的地址追加到 out 切片中,但由于它是同一个变量,我们实际上追加的是相同的地址,该地址最终包含分配给 i 的最后一个值。
所以只需要拷贝一份,让两者脱离关联就可以了。

同样的,如果这里是for循环然后启动多个goroutine, 如下:

  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. )
  7. func main() {
  8. goodsID := []uint64{1, 2, 3, 4, 5}
  9. for _, id := range goodsID {
  10. go func() {
  11. fmt.Println("正在查询商品:" + strconv.Itoa(int(id)))
  12. }()
  13. }
  14. time.Sleep(time.Second * 5)
  15. }

注意:这种bug在goland中一般会提醒,
常用的解决办法:

  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. )
  7. func main() {
  8. goodsID := []uint64{1, 2, 3, 4, 5}
  9. for _, id := range goodsID {
  10. go func(id uint64) {
  11. fmt.Println("正在查询商品:" + strconv.Itoa(int(id)))
  12. }(id)
  13. }
  14. time.Sleep(time.Second * 5)
  15. }