当前位置: 首页 > 科技观察

Go语言常见陷阱

时间:2023-03-12 16:47:18 科技观察

介绍本系列将列出一些Go面试中的常见问题。切片循环问题For循环在我们日常编码中可能会用到很多。在很多业务场景中,我们需要用到for循环处理。但是golang中的for循环在使用的时候需要注意一些问题。你能遇到吗?先看下面的代码:functestSlice(){a:=[]int64{1,2,3}for_,v:=rangea{gofunc(){fmt.Println(v)}()}time.Sleep(time.Second)}output:333那么为什么会输出这个结果呢?在golang的for循环中,循环内部创建的函数变量共享同一个内存地址,for循环总是使用同一个内存来接收循环。值变量的值。无论循环多少次,value的内存地址都是一样的。我们可以测试一下:)}输出:0xc0000b20080xc0000b20080xc0000b2008符合预期。有兴趣的可以把这段代码的汇编打印出来,可以发现循环的v一直在操作同一块内存。同样,我们会在切片循环中遇到另一个有趣的地方。你可以看到下面的代码输出了什么?functestRange3(){a:=[]int64{1,2,3}for_,v:=rangea{a=append(a,v)}fmt.Println(a)}这段代码的输出是:[123123],为什么?因为golang会在循环前复制a,然后对新复制的a进行操作,所以循环次数不会随着append的增加而增加。interface和nil比较返回空指针,但不是空指针returnresult}ifres:=doit(-1);res!=nil{fmt.Println("result:",res)}}输出结果是:result:,为什么?因为go中的变量有两个属性:type和value,所以在比较的时候,type和value也会被比较,才算相等。代码中result的类型是指针,值为nil,所以会有这样的输出。可变参数是一个空接口类型。当参数的可变参数为空接口类型时,传入空接口的slice时需要注意参数扩展的问题。functestVolatile(){vara=[]interface{}{1,2,3}fmt.Println(a)fmt.Println(a...)}输出结果为:[123]123map遍历顺序不固定.不要相信map!functestMap(){m:=map[string]string{"a":"a","b":"b","c":"c",}fork的顺序,v:=rangem{println(k,v)}}具体原因可以看下源码:map.go:mapiterinit,你会发现下面的代码是用来决定从哪里开始遍历地图的。还有一个原因是在某些情况下(比如扩容),map中会发生key的重定位和重组。遍历过程是依次遍历桶,同时依次遍历桶中的key。搬迁后,key的位置发生了明显的变化,所以遍历地图的结果不能是原来的顺序了。funcmapierinit(t*maptype,h*hmap,it*hiter){...//decidewheretostartr:=uintptr(fastrand())...}