关于range使用时有个点需要注意一下,避免踩坑

平时使用range时都是这样
for i, element := range xxxx

有没有考虑过element是如何赋值的?每次循环element是否是新生成临时变量?

先看看如下代码的运行结果

idNum := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

waitGrp := sync.WaitGroup{}
for index, unit := range idNum {
    waitGrp.Add(1)

    fmt.Printf("unit(%d) addr:%p value:%d \n", index, &unit, unit)

    /*
        go func(num int) {
            fmt.Printf("------Num:%d, unit addr:%p \n", num, &num)
            waitGrp.Done()
        }(unit)
    */

    go func() {
        fmt.Printf("******Num:%d, unit addr:%p \n", unit, &unit)
        waitGrp.Done()
    }()
}

waitGrp.Wait()

输出结果如下

unit(0) addr:0xc0000ae040 value:0 
unit(1) addr:0xc0000ae040 value:1 
unit(2) addr:0xc0000ae040 value:2 
unit(3) addr:0xc0000ae040 value:3 
unit(4) addr:0xc0000ae040 value:4 
unit(5) addr:0xc0000ae040 value:5 
unit(6) addr:0xc0000ae040 value:6 
unit(7) addr:0xc0000ae040 value:7 
unit(8) addr:0xc0000ae040 value:8 
unit(9) addr:0xc0000ae040 value:9 
unit(10) addr:0xc0000ae040 value:10 
unit(11) addr:0xc0000ae040 value:11 
unit(12) addr:0xc0000ae040 value:12 
unit(13) addr:0xc0000ae040 value:13 
unit(14) addr:0xc0000ae040 value:14 
unit(15) addr:0xc0000ae040 value:15 
******Num:14, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:3, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:15, unit addr:0xc0000ae040 
******Num:10, unit addr:0xc0000ae040 

看第一部分输出

unit(0) addr:0xc0000ae040 value:0 
unit(1) addr:0xc0000ae040 value:1 
unit(2) addr:0xc0000ae040 value:2 
unit(3) addr:0xc0000ae040 value:3 
unit(4) addr:0xc0000ae040 value:4 
unit(5) addr:0xc0000ae040 value:5 
unit(6) addr:0xc0000ae040 value:6 
unit(7) addr:0xc0000ae040 value:7 
unit(8) addr:0xc0000ae040 value:8 
unit(9) addr:0xc0000ae040 value:9 
unit(10) addr:0xc0000ae040 value:10 
unit(11) addr:0xc0000ae040 value:11 
unit(12) addr:0xc0000ae040 value:12 
unit(13) addr:0xc0000ae040 value:13 
unit(14) addr:0xc0000ae040 value:14 
unit(15) addr:0xc0000ae040 value:15 

就可以明白了,element的地址是不变的,每次都是对同一个变量赋值的
所以在routine中直接访问element时得到的是瞬时当前的值。
如果想要在routine中使用每次循环的element值,将element值传入就可以了

go func(num int) {
    fmt.Printf("------Num:%d, unit addr:%p \n", num, &num)
            waitGrp.Done()
}(unit)

麦穗儿
127 声望15 粉丝

程序猿以技术为本