github中100-go-mistakes:https://github.com/teivah/100-go-mistakes
在 Go 语言中,使用 map 前必须进行初始化,否则会报错。常见的 map 初始化错误包括:
在 Go 语言中,使用 make 函数进行 map 的初始化,例如:
m := make(map[string]int)
如果不使用 make 函数进行初始化,而是使用下面的代码:
m := map[string]int{}
虽然语法上没有错误,但是这样会导致运行时错误,因为 map 没有被正确初始化。
当将 map 作为函数的参数传递时,必须在函数中进行初始化,例如:
func foo(m map[string]int) {if m == nil {m = make(map[string]int)}// ...
}
在使用 map 时,如果 map 没有被正确初始化,会返回 nil。如果没有进行 nil 判断,会导致运行时错误,例如:
在这段代码中,定义了一个名为 Course 的结构体,它具有两个字段:Name 和 Desc,均为字符串类型。接下来,定义了一个 String() 方法来返回 Course 结构体的字符串表示形式。
在 main() 函数中,通过使用 new() 关键字创建了一个名为 c 的指向 Course 结构体的空指针。接着,调用 fmt.Println() 函数来输出 c,这将自动调用 c 的 String() 方法并打印出其字符串表示形式。
由于 c 是一个空指针,其指向的 Course 结构体尚未被初始化,因此 Name 和 Desc 字段都将是空字符串。因此,程序将输出空字符串。具体输出结果取决于实现方式和环境。
package mainimport "fmt"type Course struct {Name stringDesc string
}// 绑定结构体规范
func (c *Course) String() string {return c.Name + c.Desc
}func main() {//结构体的空指针//c := new(Course)c := &Course{}fmt.Println(c.String())
}
在这段代码中,定义了一个 goodsID 切片来存储商品的 ID。接着,在 for 循环中使用 range 迭代器来遍历 goodsID,对于每个商品 ID,都创建了一个新的匿名函数并使用 go 关键字来并发地执行它们。
但是,由于匿名函数中的 id 变量是对循环迭代器变量的引用,所以每个匿名函数实际上都在引用相同的 id 变量。在并发执行的过程中,这些匿名函数将共享这个 id 变量,导致输出的结果不是我们期望的。
package mainimport ("fmt""strconv""time"
)// for循环的坑 -> 指针
func main() {//var out []*int//for 循环的临时变量会复用//for i := 0; i < 3; i++ {// tmp := i// out = append(out, &tmp)//}//for _, value := range out {// fmt.Println(*value)//}//假设我又一批商品id,我现在想要拿到这批商品id的详情,并发启动多个goroutine去拿这批商品的详情goodsID := []uint64{1, 2, 3, 4, 5}for _, id := range goodsID {//tmp := id//值传递go func(id uint64) {fmt.Println("正在查询商品:" + strconv.Itoa(int(id)))}(id)}time.Sleep(time.Second * 5)
}
为了解决这个问题,我们可以在循环中创建一个新的变量来存储商品 ID,并将其传递给匿名函数。例如:
for _, id := range goodsID {go func(gID uint64) {fmt.Println("正在查询商品:" + strconv.Itoa(int(gID)))}(id)
}