forfor rangefor range
情形 . 一
> for range + 闭包
package main
import (
"fmt"
"time"
)
func main() {
str := []string{"I","am","Ethan"}
for _,v := range str{
go func() {
fmt.Println(v)
}()
}
time.Sleep(3 * time.Second)
}
----------
输出结果:
Ethan
Ethan
Ethan
程序设计的原意是遍历字符串切片并将其打印出来,可是输出结果却只输出了切片的最后一个元素.
println(v)println(v)
如果要正确打印,在定义闭包的时候要定义一个参数,将v作为参数传递进去.修改后代码如下:
package main
import (
"fmt"
"time"
)
func main() {
str := []string{"I","am","Ethan"}
for _,v := range str{
go func(v string) {
fmt.Println(v)
}(v)
}
time.Sleep(3 * time.Second)
}
此外,输出结果不一定是 i am Ethan,因为goroutine执行顺序有go runtime调度器决定
情形 . 二
> 操作map,原理和情形一类似
package main
import "fmt"
func main() {
slice := []int{0, 1, 2, 3}
myMap := make(map[int]*int)
for index , value := range slice {
myMap[index] = &value
}
prtMap(myMap)
}
func prtMap(myMap map[int]*int) {
for key, value := range myMap {
fmt.Printf("map[%v]=%v\n", key, *value)
}
}
----------
输出结果:
map[0]=3
map[1]=3
map[2]=3
map[3]=3
原因解释:但是由输出可以知道,映射的值都相同且都是3。其实可以猜测映射的值都是同一个地址,遍历到切片的最后一个元素3时,将3写入了该地址,所以导致映射所有值都相同。
其实真实原因也是如此,因为for range创建了每个元素的副本,而不是直接返回每个元素的引用,如果使用该值变量的地址作为指向每个元素的指针,就会导致错误,在迭代时,返回的变量是一个迭代过程中根据切片依次赋值的新变量,所以值的地址总是相同的,导致结果不如预期。
做一下小小的修改就能得到我们的预期结果:
package main
import "fmt"
func main() {
slice := []int{0, 1, 2, 3}
myMap := make(map[int]*int)
for index , value := range slice {
v := value
myMap[index] = &v
}
prtMap(myMap)
}
func prtMap(myMap map[int]*int) {
for key, value := range myMap {
fmt.Printf("map[%v]=%v\n", key, *value)
}
}