range

为什么下面的 range 遍历只执行了 3 次?

func main() {
    nums := []int{1, 2, 3}
    for i := range nums {
        nums = append(nums, i)
        fmt.Println(nums)
    }
    // 输出:
    // [1 2 3 0]
    // [1 2 3 0 1]
    // [1 2 3 0 1 2]
}

因为 range 遍历的是切片的副本,而不是切片本身。在遍历的过程中,切片的长度会发生变化,但是遍历的次数在遍历开始时就已经确定了。

range 变量作用域问题

package main

import "sync"
import "time"

func main() {
    wg := sync.WaitGroup{}
    values := []int{1, 2, 3}
    for _, v := range values {
        go func() {
            fmt.Println(v)
        }()
    }
    <-time.Tick(time.Second)
}

Go 1.22 之前的版本会输出:

3
3
3

因为在 range 循环中获取返回变量的地址都完全相同(虽然有多个值),变量 v 的作用域覆盖了整个循环体,每次循环只是更新了 v 的值,而没有创建新的变量。

Go 1.22 版本修复了这个问题,循环时的变量作用域被修改为每次循环都创建一个独立的变量

最后更新于