Golang for循环 变量使用注意 一则

今天开发的时候, 排查一个不能必现的BUG, 花了不少时间, 最终发现是对于基本语法理解不深刻导致的. 这里记录一下, 以博各位看官一乐.

注意点: for 循环里面, 变量是重复赋值的, 不要想当然的当作每次创建一个新的局部变量. 所以在 循环体 里面千万不能取引用. 类似的道理, 在 循环体里面创建 goroutine, 也一定要记得将参数拷贝带进去, 否则会绑定到循环最后复制变量.

ws := make(map[string]io.Writer)
for k, c := range m {
    // ERROR 最终都指向最后一个
    ws[k] = &Writer{c: &c} // 这里其实原来是 func (c *Conf) New() ... 不影响结果

    // OK 拷贝变量, 而不是指针引用
    w := &Writer{c: c}
    // OK 拷贝一份局部变量
    c2 := c
    w := &Writer{c: c2}

    // ERROR
    go func() {
        w := &Writer{c: c}
        w.Start()
    }

    // DO
    go func(c Conf) {
        w := &Writer{c: c}
        w.Start()
    }(c)
}

其实最近也有看到相关的文章, 不过之前看了没有什么切身体会, 工作上遇到了才有深刻印象.

Go Spec 文档也曾对此做过修订.

类似的PHP的坑之前也记录过. 发誓以后各种语言都不再踩类似的坑了~

References

HOME