当前位置: 首页 > 面试题库 >

为什么Golang在goroutines中对闭包的处理方式不同?

裘丰
2023-03-14
问题内容

考虑以下Golang代码(也在Go Playground上):

package main

import "fmt"
import "time"

func main() {
    for _, s := range []string{"foo", "bar"} {
        x := s
        func() {
            fmt.Printf("s: %s\n", s)
            fmt.Printf("x: %s\n", x)
        }()
    }
    fmt.Println()
    for _, s := range []string{"foo", "bar"} {
        x := s
        go func() {
            fmt.Printf("s: %s\n", s)
            fmt.Printf("x: %s\n", x)
        }()
    }
    time.Sleep(time.Second)
}

此代码产生以下输出:

s: foo
x: foo
s: bar
x: bar

s: bar
x: foo
s: bar
x: bar

假设这不是一些奇怪的编译器错误,我很好奇为什么a)s的值在goroutine版本中的解释与常规func调用中的不同,并且b)为什么将其分配给循环内的局部变量起作用?两种情况。


问题答案:

Go中的闭包在词法范围内。这意味着闭包内从“外部”范围引用的任何变量都不是副本,而是实际上是引用。一for环竟重复使用相同的变量多次,所以你介绍的读/写之间的竞争条件s变量。

但是x正在分配一个新变量(带有:=)并进行复制s,这导致每次都是正确的结果。

通常,最佳做法是传递所需的任何参数,以使您没有引用。例:

for _, s := range []string{"foo", "bar"} {
    x := s
    go func(s string) {
        fmt.Printf("s: %s\n", s)
        fmt.Printf("x: %s\n", x)
    }(s)
}


 类似资料:
  • 问题内容: 我正在阅读,发现在关闭正文之后,自己对“()”并不真正了解: 在: func(ch chan int){ch < -ACK } (replyChan) ` 在的示例中: 我不清楚关闭主体后添加和使用“()”的原因,希望有人可以清楚地解释一下。 问题答案: 这并不是说必须(仅)一个后添加 封 在。defer语句的语言规范要求其“ Expression” 始终 必须是函数调用。 为什么会这

  • 我想知道为什么Spring Boot处理404时没有发现不同。 无现有路径示例 我用curl在一个不存在的路径上提出请求: 现在我请求一个不存在的实体的endpoint: 所以我的问题是:为什么SpringBoot只在找不到实体的情况下发送一个简单的404状态?我希望看到一条好消息:在我的text/html错误页面上找不到实体或类似的内容,或者在json请求的情况下看到json错误对象。。。对于路

  • 为什么在JS中, React处理像这样导入 而 节点处理这样的导入 这纯粹是一种惯例吗? 如果是,它们是否可以交换? 如果不是,为什么这样做很重要? 它们在幕后有什么区别,例如性能?

  • 问题内容: 我注意到在Swift 2.2中,标为non-escaped的闭包不需要explicit 。在Swift 3中,默认情况下,所有闭包都是不转义的,如果您希望它们能够转义,现在要求将其标记出来。 鉴于默认情况下Swift 3中的所有闭包都是非转义的,为什么它们需要显式的? 问题答案: 在Swift 3中,默认情况下所有闭包都不转义 不,在Swift 3中,默认情况下仅闭包 函数参数 (即,

  • 问题内容: 我们在其他语言中认为是理所当然的,并且几乎期望它可以继续工作,但不会起作用-这样做是如此自然,所以为什么编译器不满意?只是有时候感觉就像不耐烦。 递增值的唯一方法是将其放在单独的行中? http://play.golang.org/p/_UnpZVSN9n 问题答案: 而在golang声明,不表达

  • 闭包是一个特殊的匿名函数,它是匿名函数和相关引用环境组成的一个整体 也就是说只要匿名函数中用到了外界的变量,那么这个匿名函数就是一个闭包 package main import "fmt" func main() { num := 10 a := func() { num++ // 在闭包中用到了main函数中的num, 所以这个匿名函数就是一个闭包