先看这个代码有问题吗?

一道面试实战题-Go_数组


文章目录

  • 先看这个代码有问题吗?
  • 问题
  • 正确的是
  • 如果不传递 i 给 goroutine,还会出现什么问题 ?


问题

  1. 在循环中启动了 goroutine (go func() {…}),但没有等待这些 goroutine 完成
  2. 主函数可能在所有 goroutine 执行前就结束了
  3. 循环变量 i 被所有 goroutine 共享,可能导致输出结果不符合预期

正确的是

package main

import (
    "fmt"
    "sync"
)

func main() {
    testRange2()
}

func testRange2() {
    arr := make([]int, 10)
    var wg sync.WaitGroup
    
    for i := range arr {
        wg.Add(1)
        go func(val int) {
            defer wg.Done()
            fmt.Println(val)
        }(i)  // 将 i 作为参数传递给 goroutine
    }
    
    wg.Wait()  // 等待所有 goroutine 完成
}

如果不传递 i 给 goroutine,还会出现什么问题 ?

如果不将循环变量 i 作为参数传递给 goroutine,会出现一个常见且容易被忽视的问题:所有 goroutine 可能会打印出相同的值,通常是数组的最后一个索引值(在这个例子中是 9)。
这个问题的原因是:

  1. 闭包变量捕获机制:Go 中的闭包会捕获外部变量的引用,而不是值的副本。
  2. 循环变量共享:所有 goroutine 共享同一个循环变量 i 的引用。
  3. 执行时机:goroutine 的实际执行可能会延迟到循环结束后才开始。

循环结束时的变量状态:当循环结束时,i 的值已经变成了 10(超出了数组范围),或者在 range 循环的情况下是 9(最后一个索引)。