这段go代码是什么意思?

我在看别人代码的时候:

    for i := 0; i < 100; i++ {
        go func(i int) {
            fmt.Println(i)
        }(i)
    }

我知道

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

是遍历 0- 99 次。

但是:里面的这个代码是什么意思?是指的开辟多线程异步执行吗?

        go func(i int) {
            fmt.Println(i)
        }(i)

如果是开多线程,为何不用下面两种方式:

go func() {
            fmt.Println(i)
        }()
go func(i int) {
            fmt.Println(i)
        }()
阅读 4.2k
5 个回答

是开协程,不是线程。

这种写法叫闭包函数。你自己分别按这两种写法运行看看就知道差别了。

可能形参实参都叫 i 所以你迷糊了,换个名字看可能更清晰:

for outer := 0; outer < 100; outer++ {
    go func(inner int) {
        fmt.Println(inner)
    }(outer)
}

JS 中也有类似的问题,也是面试题中常见的问题之一:

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i)
    });
}

for (var i = 0; i < 10; i++) {
    setTimeout((function(i) {
        console.log(i);
    })(i));
}

本质就是为了防止变量作用域污染。

最近也在学习Golang,其中go关键字是创建协程的意思。
你这段代码的例子中,go,代表开启协程,后面定义一个函数,作为协程要执行的代码,最后是向函数传的参数。
类似的例子可以参考:https://books.studygolang.com...

学习了@然后去远足 的答案~

以下你提到的第一种写法:

for i := 0; i < 100; i++ {
    go func() {
         fmt.Println(i)
    }()
}

这样写的输出结果是不可预测的, 以下是我的机器的部分运行结果:

32
56
56
25
70
72
72     
...

甚至不主动阻塞 goroutine 的话没有任何输出,这是因为在 for 循环中使用 go 创建了协程, 但是协程创建和运行需要耗费时间,此时 for 可能已经循环了很多次(我的例子中为33次), 此时第一个要运行的 goroutine 运行时才会去获取 i 的值(此时 i= 32), 所以打印不符合你的预期(这就是闭包, 可参考 https://zhuanlan.zhihu.com/p/...)

你提到的第二种写法:

for i := 0; i < 100; i++ {
    go func(i int) {  // 匿名函数定义参数
         fmt.Println(i)
    }()   // 这里需要传入参数
}

这种写法本来就是错误的,请学习 golang 的匿名函数的使用。

学过前端JS的应该很容易理解,这就是闭包,也就是独立作用域。
Go也借鉴了动态语言的一些特点。
最好的理解是,将两种结果都打印输出,看下结果差异性。

感觉题主是初学,学习编程语言,建议把官方文档看三遍,第一遍囫囵吞枣,了解个大概,重点是数据类型(某些地方不理解的,可能是还没涉及到,后面自会学到);第二遍回头重看,可以看得细一些,重点是函数相关;第三遍结合自身情况,查漏补缺,可以适当深入。
当然别光看,得敲代码,一行一行的敲。

go func(i int) {
    fmt.Println(i)
}()

这个写法跟JS其实挺像的。但是上面这代码应该运行不起来,因为func里面有一个i的参数,但是()里面是空的,没有传参数,所以就运行不起来。这代码里面的fmt.Println(i),i是传参数进来的i,而不是for循环出来的i。在func里面无法获取for外面的i变量,所以只能通过下面这种写法,把i传递进去。

go func(i int) {
    fmt.Println(i)
}(i)
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏