0°

golang错题集

简介: 本文即Go语言的那些坑三。

本文即Go语言的那些坑三。

不要对Go并发函数的执行时机做任何假设

请看下列的列子:

1import (
 2    "fmt"
 3    "runtime"
 4    "time"
 5)
 6func main(){
 7    names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
 8    for _, name := range names{
 9        go func(){
10            fmt.Println(name)
11        }()
12    }
13    runtime.GOMAXPROCS(1)
14    runtime.Gosched()
15}

请问输出什么?
答案:

1annei
2annei
3annei
4annei
5annei

为什么呢?是不是有点诧异?
输出的都是“annei”,而“annei”又是“names”的最后一个元素,那么也就是说程序打印出了最后一个元素的值,而name对于匿名函数来讲又是一个外部的值。因此,我们可以做一个推断:虽然每次循环都启用了一个协程,但是这些协程都是引用了外部的变量,当协程创建完毕,再执行打印动作的时候,name的值已经不知道变为啥了,因为主函数协程也在跑,大家并行,但是在此由于names数组长度太小,当协程创建完毕后,主函数循环早已结束,所以,打印出来的都是遍历的names最后的那一个元素“annei”。
如何证实以上的推断呢?
其实很简单,每次循环结束后,停顿一段时间,等待协程打印当前的name便可。

1import (
2    "fmt"
3    "runtime"
4    "time"
5)
6func main(){
7    names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
8    for _, name := range names{
9        go func(){
10            fmt.Println(name)
11        }()
12        time.Sleep(time.Second)
13    }
14    runtime.GOMAXPROCS(1)
15    runtime.Gosched()
16}

打印结果:

1lily
2yoyo
3cersei
4rose
5annei

以上我们得出一个结论,不要对“go函数”的执行时机做任何的假设,除非你确实能做出让这种假设成为绝对事实的保证。
假设T类型的方法上接收器既有T类型的,又有T指针类型的,那么就不可以在不能寻址的T值上调用T接收器的方法

请看代码,试问能正常编译通过吗?

1import (
 2    "fmt"
 3)
 4type Lili struct{
 5    Name string
 6}
 7func (Lili *Lili) fmtPointer(){
 8    fmt.Println("poniter")
 9}
10func (Lili Lili) fmtReference(){
11    fmt.Println("reference")
12}
13func main(){
14    li := Lili{}
15    li.fmtPointer()
16}

答案:

点击了解更多,查看剩余内容

了解更多

关键字:Go语言  错题  技巧  答案

本文由【有】发布于开源中国,原文链接:https://my.oschina.net/u/4431452/blog/3147103

全部评论: 0

    我有话说: