通过两个例子介绍一下 Golang For Range 循环原理(转)

[复制链接]
查看11 | 回复0 | 2021-1-27 05:57:28 | 显示全部楼层 |阅读模式
下面的代码是死循环么?
语法糖
下面的代码有什么问题么?
切片ForRange原理
其它语法糖
map
channel
数组
字符串
下面的代码是死循环么?
funcmain(){
v:=[]int{1,2,3}
fori:=rangev{
v=append(v,i)
}
}
上面的代码先初始化了一个内容为1、2、3的slice,然后遍历这个slice,然后给这个切片追加元素。随着遍历的进行,数组v也在逐渐增大,那么这个for循环是一个死循环么?
答案是否。只会遍历三次,v的结果是[0,1,2]。并不是死循环,原因就在于forrange实现的时候用到了语法糖。
语法糖
语法糖(Syntacticsugar),也译为糖衣语法,是由英国计算机科学家彼得·蘭丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。
对于切片的forrange,它的底层代码就是:
//for_temp:=range
//len_temp:=len(for_temp)
//forindex_temp=0;index_temp%d\n",k,*v)
}
这也是实际编码中有可能会遇到的问题,循环切片,index和value地址一开始分配好后,后面还是那个地址,把切片值的地址保存到myMap中,这样的操作结果是:
=====newmap=====
0=>3
1=>3
2=>3
3=>3
结果完全一样,都是最后一次遍历的值。通过上面的底层代码看下,遍历后的值赋给了value,而在我们的例子中,会把value的地址保存到myMap的值中。这里的value是个「全局变量」,所以赋完值之后myMap里面所有的值都是value,所以结构都是一样的而且是最后一个值。
注意,这里必须是保存指针才会有问题,如果直接保存的是value,因为Golang是值拷贝,所以值会重新复制再保存,这种情况下结果就会是正确的了。
切片ForRange原理
总结一下,通过ForRange遍历切片,首先,计算遍历次数(切片长度);每次遍历,都会把当前遍历到的值存放到一个全局变量index中。
其它语法糖
另外,ForRange不光支持切片。其它的语法糖底层代码。
map
//Loweraforrangeoveramap.
//Theloopwegenerate:
//varhitermap_iteration_struct
//formapiterinit(type,range,&hiter);hiter.key!=nil;mapiternext(&hiter){
//index_temp=*hiter.key
//value_temp=*hiter.val
//index=index_temp
//value=value_temp
//originalbody
//}
channel
//Loweraforrangeoverachannel.
//Theloopwegenerate:
//for{
//index_temp,ok_temp=
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行