用过golang的同学,相信对「for range」是再熟悉不过了,可以说在任何语言中,循环遍历都是常用的再也不能常用的一种方式,不过最近发现了一个问题,其实挺坑的,今天总结一下,希望对您有用。
10年积累的网站制作、做网站经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有浚县免费网站建设让你可以放心的选择与我们合作。
咱们废话不用多说,直接看例子。
dataFromDb := []int{1,2,3} //从数据库取出来的数据
var finalData []*int //目标数据
for _,i := range dataFromDb{
finalData = append(finalData, &i)
}
for _, final := range finalData{
fmt.Println(*final)
}
上面的例子很简单
直观的感受,上面简直是一段简单的不能再简单的代码了,相信大家会脱口而出最后finalData的值是1,2,3,但是我们实际运行一下,结果输出的却是
~/Sites/test » go run main.go
3
3
3
结果输出的全部都是3,显然这与我们的认知是不符合的,但是为什么会这样呢?如果想弄清这个原理,首先我们得知道for range到底干了什么。
要想了解一个函数的原理,最好的方式就是看源码,我们来看一看for range到底干了什么。
源码来自于 go 编译器的 「gc.walkrange」, 编译器对 for range 表达式的解析如下:
// a为原始slice
ha := a
hv1 := 0
// slice长度
hn := len(a)
v1 := 0
v2 := nil // for i,v := range 中的 v
for ; h1 < hn ; h1++ {
tmp := ha[hv1]
v1,v2 := hv1,tmp
}
for _,i := range dataFromDb{
finalData = append(finalData, &i)
}
对于i来说,相当于 var i int,然后在循环的过程中 i=1,i=2,i=3 &i是指向i的地址,「所以&i是永远不会变的」。
其实解决办法很简单,引入「中间变量」即可,代码改成下面这个样子。
dataFromDb := []int{1,2,3}
var finalData []*int
for _,i := range dataFromDb{
temp := i //引入中间变量,每一次循环都重新开辟了一个temp的空间
finalData = append(finalData, &temp)
}
for _, final := range finalData{
fmt.Println(*final)
}
代码加入了「中间变量temp」temp:=i等价于。
var temp int
temp = 1
s := []int{1, 2, 3}
for _, v := range s {
go func() {
fmt.Println(v) // 输出结果3 3 3
}()
}
select {}
大家可以想一想上面这段代码会输出什么
3
3
3
输出结果居然全部都是最后一个值,这是为什么呢?
在没有将变量 v 的拷贝值传进匿名函数之前,只能获取最后一次循环的值,这是新手最容易遇到的坑。
解决办法其实比较简单,在闭包函数上增加参数,并且与go rountine绑定即可。
s := []int{1, 2, 3}
for _, v := range s {
go func(v int) {
fmt.Println(v) // 输出结果3 1 2
}(v)
}
select {}
名称栏目:原来Golang的Foreach这么坑!
网页网址:http://www.shufengxianlan.com/qtweb/news42/121492.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联