golang中的那些坑之迭代器中的指针使用

今天在编写代码的时候,遇到了一个莫名其妙的错误,debug了半天,发现这是一个非常典型且易犯的错误.记之

示例代码:

package main
import "fmt"
type aa struct {
        x, y int 
}
type bb struct {
        member aa
}
func main() {
        m := []*aa{}
        pool := []bb {
                {
                        member: aa{x : 1,y : 1,},
                },
                {
                        member: aa{x : 2,y : 2,},
                },
                {
                        member: aa{x : 3,y : 3,},
                },
        }
        for _, p := range pool {
                m = append(m, &p.member)
        }
        for _, ele := range m { 
                ele.x = ele.x + 1 
                ele.y = ele.y + 1 
        }

        for _, ele := range m { 
                fmt.Printf("x=%d, y=%d\n", ele.x, ele.y)
        }
}

上面这段代码的运行结果是什么?也许你会立马答出来是:

x=2, y=2

x=3, y=3

x=4, y=4

运行一下就知道这个答案是错的.正确的运行结果是:

x=6, y=6

x=6, y=6

x=6, y=6

 

那么到底错在哪呢?原来在数组m中,它的三个元素是同一个指针.原来在下面这段代码中,golang是新建了一个变量p, 每次将该数组的元素

赋值给这个p,而p的地址自然是恒定的,因此最后m中的元素都是这个p的成员变量member的地址.

       for _, p := range pool {
                m = append(m, &p.member)
        }

 

这个例子告诉我们,在golang的数组/map迭代操作中,如果在迭代体中需要访问数组/map元素的指针,那么千万要小心了.这类bug非常难以检测.

posted @ 2018-10-13 14:44  ElNinoT  阅读(1293)  评论(1编辑  收藏  举报