为了账号安全,请及时绑定邮箱和手机立即绑定

golang 不寻常的 Go 构造:创建可重用的名称:名称:= 名称……某事

golang 不寻常的 Go 构造:创建可重用的名称:名称:= 名称……某事

Go
jeck猫 2021-08-10 16:07:15
我在某处看到了这个构造,用于在向函数发送数据时重用“名称”。我正在使用一个数据库,需要发送大量要处理的“命名”缓冲区。这个结构看起来很完美,但我无法工作,也不记得我在哪里看到过它的讨论。任何帮助,将不胜感激。文本的要点是,每次使用此结构时,名称都会反复使用,但每个实例实际上都将拥有它自己的集合。我只记得它是 name := name ..then 的东西。我在这里迷路了。
查看完整描述

2 回答

?
慕村225694

TA贡献1880条经验 获得超4个赞

您肯定是指创建循环变量的副本。通常,在此代码中:


for i := 0; i < 100; i++ {

    go func() {

        fmt.Println(i)

    }

}

i将在所有 goroutines 中引用循环变量,所以如果 goroutines 产生,然后循环在它们调用之前继续运行fmt.Println(i),i当它们调用它时将与它们从循环中产生时不同。正如你提到的,解决这个问题的一种方法是:


for i := 0; i < 100; i++ {

    i := i

    go func() {

        fmt.Println(i)

    }

}

添加的行i := i引入了一个名为 的局部变量i,并将其设置为等于循环变量i。这是两个不同的变量。你还不如说j := i然后用j。我倾向于认为使用i := i更令人困惑,但有些人更喜欢它。在任何情况下,鉴于它是一个局部变量,每个循环都有一个不同的实例,这意味着每个 goroutine 都会看到它自己的唯一实例,不会被更改。


虽然这个习语可以在Effective Go 中找到(在页面上搜索“req := req”),但让我澄清一些事情:这是令人困惑的,应该避免。我不知道为什么 Go 作者认为引入这个习语是个好主意,在我看来,应该避免。为什么?因为有一种更简洁的方法可以完成更容易理解的相同事情:


for i := 0; i < 100; i++ {

    go func(i int) {

        fmt.Println(i)

    }(i)

}

在这个版本中,匿名函数接受一个整数参数,当它在 goroutine 中产生时,循环变量i作为该参数传递。人们对这些语义有了更扎实的理解,因此更容易看到它的作用并理解它为什么起作用。如果这仍然令人困惑,我建议更改参数名称:


for i := 0; i < 100; i++ {

    go func(j int) {

        fmt.Println(j)

    }(i)

}

我认为这两种方法更容易理解,应该使用而不是您提到的示例。


查看完整回答
反对 回复 2021-08-10
?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

你的意思是这样的构造:


func foo() {

    var bar // some variable


    go func() {

        bar := bar // copy bar into inner scope

    }()

}


查看完整回答
反对 回复 2021-08-10
  • 2 回答
  • 0 关注
  • 186 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信