MST

星途 面试题库

面试题:Go闭包与并发场景下的常见错误及规避

考虑以下Go代码,在并发环境中使用闭包: ```go package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup var data []int for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() data = append(data, i) }() } wg.Wait() fmt.Println(data) } ``` 这段代码可能会出现什么问题?如何使用闭包来正确地实现将0到4添加到 `data` 切片中?说明这样修改的原理。
19.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 问题分析
    • 在这段代码中,for 循环启动了5个goroutine,这些goroutine共享变量 i。由于goroutine是并发执行的,在 for 循环结束后,i 的值已经变为5,当goroutine执行 data = append(data, i) 时,它们追加到 data 切片中的值都是5,而不是预期的0到4。
  2. 正确实现
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    var data []int
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(j int) {
            defer wg.Done()
            data = append(data, j)
        }(i)
    }
    wg.Wait()
    fmt.Println(data)
}
  1. 原理说明
    • 通过在闭包函数的参数列表中传入 i,并将这个传入的参数命名为 j(这里 j 可以是任意合法变量名),每个goroutine就有了自己独立的 j 变量,其值是在goroutine启动时 i 的值。这样,每个goroutine在执行 data = append(data, j) 时,就会将正确的值追加到 data 切片中,实现了将0到4添加到 data 切片的目的。这是因为每次调用闭包函数时,i 的值作为参数传递给闭包,在闭包内部形成了独立的变量,避免了所有goroutine共享同一个 i 变量带来的问题。