转载自:https://blog.cyeam.com/golang/2018/10/30/for-interals
有以下代码:
func main() {
v := []int{1, 2, 3}
for i := range v {
v = append(v, i)
}
}
这个代码会遍历v的切片,在遍历的过程中append元素给切片,那么它会不会死循环呢?
答案是否定的,一下是for range的底层代码:
// for_temp := range
// len_temp := len(for_temp)
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// value_temp = for_temp[index_temp]
// index = index_temp
// value = value_temp
// original body
// }
可以看到在一开始切片的长度就已经被获取了,所以最终是做了切片的长度(3次)的循环
再看一段代码:
func main() {
slice := []int{0, 1, 2, 3}
myMap := make(map[int]*int)
for index, value := range slice {
myMap[index] = &value
fmt.Println(&value)
}
fmt.Println("=====new map=====")
for k, v := range myMap {
fmt.Printf("%d => %d\n", k, *v)
}
}
这段代码定义了一个key为int,value为*int的map,想要把切片的index与其指向元素的地址传进去,,结果会发现输出的三个元素数值是相同的,都为最后的元素3:
=====new map=====
0 => 3
1 => 3
2 => 3
3 => 3
造成这种情况的原因是for range返回的这个value并不是切片本身的value,而是其value的一个复制,因为:再golang中大多数的函数都是值传递而不是指针传递,在传递过程中会对变量进行一次复制,以保证原数据不会被其他行为修改。所以,存放在map中的都是一个复制过后的变量而非切片原来的元素,而这个变量又是全局变量,它的地址是始终不变的,改变的只是它所指向的数值,因为数值改变而地址不变,所以这种写法会出现这种错误,但是如果在map中不存在指针而是存放数值就没有问题了:
func main() {
slice := []int{0, 1, 2, 3}
myMap := make(map[int]int)
for index, value := range slice {
myMap[index] = value
fmt.Println(&value)
}
fmt.Println("=====new map=====")
for k, v := range myMap {
fmt.Printf("%d => %d\n", k, v)
}
}
输出为:
0xc000058080
0xc000058080
0xc000058080
0xc000058080
=====new map=====
0 => 0
1 => 1
2 => 2
3 => 3