良许Linux教程网 干货合集 讲解一下Go 语言常见的一些坑

讲解一下Go 语言常见的一些坑

本篇文章重点为大家讲解一下Go 语言常见的一些坑,有需要的小伙伴可以参考一下。

讲解一下Go 语言常见的一些坑

切片循环问题

For循环在我们日常编码中可能用的很多。在很多业务场景中我们都需要用for循环处理。但golang中的for循环在使用上需要注意一些问题,大家可否遇到。先看下边这一段代码:

func testSlice() {
   a := []int64{1,2,3}
   for _, v := range a {
       go func() {
           fmt.Println(v)
       }()
   }
   
   time.Sleep(time.Second)
}

output: 3 3 3

那么为什么会输出的是这个结果呢?

在golang的for循环中,循环内部创建的函数变量都是共享同一块内存地址,for循环总是使用同一块内存去接收循环中的的value变量的值。不管循环多少次,value的内存地址都是相同的。我们可以测试一下:

func testSliceWithAddress() {
   a := []int64{1,2,3}
   for _, v := range a {
       go func() {
           fmt.Println(&v)
       }()

   }

   time.Sleep(time.Second)
}

output:
       0xc0000b2008
       0xc0000b2008
       0xc0000b2008

符合预期。如果大家比较感兴趣的话可以去将这段代码的汇编打印出来,就可以发现循环的v一直在操作同一块内存。

同样的,在slice循环这块我们还会遇见另一个有趣的地方,大家可以看看下边这段代码输出什么?

func testRange3() {
   a := []int64{1,2,3}
   for _, v := range a {
       a = append(a, v)
   }

   fmt.Println(a)
}

这段代码的输出结果是:[1 2 3 1 2 3],为什么呢?因为golang在循环前会先拷贝一个a,然后对新拷贝的a进行操作,所以循环的次数不会随着append而增多。

interface和nil比较

比如返回了一个空指针,但并不是一个空interface

func testInterface() {
   doit := func(arg int) interface{} {
       var result * struct{} = nil
       if arg > 0 {
           result = &struct{}{}
       }

       return result
   }

   if res := doit(-1); res != nil {
       fmt.Println("result:", res)
   }
}

输出结果为:result: ,为什么呢?因为在go里边变量有类型和值两个属性,在比较的时候也会比较类型和值都相同才会认为相等。代码中result的类型是指针,值是nil,所以会有这样的输出。

可变参数是空接口类型

当参数的可变参数是空接口类型时,传入空接口的切片时需要注意参数展开的问题。

func testVolatile() {
   var a = []interface{}{1, 2, 3}

   fmt.Println(a)
   fmt.Println(a...)
}
输出结果为:

[1 2 3]
1 2 3

map遍历时顺序不固定

不要相信map的顺序!

func testMap() {
   m := map[string]string{
       "a""a",
       "b""b",
       "c""c",
   }

   for k, v := range m {
       println(k, v)
   }
}

具体原因大家可以看一下源码:map.go:mapiterinit,就会发现下边这个代码用来决定从哪开始遍历map。另一个原因是map 在某些特定情况下(例如扩容),会发生key的搬迁重组。而遍历的过程,就是按顺序遍历bucket,同时按顺序遍历bucket中的key。搬迁后,key的位置发生了重大的变化,所以遍历map的结果就不可能按原来的顺序了。

func mapiterinit(t *maptype, h *hmap, it *hiter) {
       ......
   // decide where to start
   r := uintptr(fastrand())
       ......
}

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部