对于所有的 range 循环,Go 语言都会在编译期将原切片或者数组赋值给一个新变量 ha,在赋值的过程中就发生了拷贝,而我们又通过 len 关键字预先获取了切片的长度,所以在循环中追加新的元素也不会改变循环执行的次数,这也就解释了循环永动机一节提到的现象。
而遇到这种同时遍历索引和元素的 range 循环时,Go 语言会额外创建一个新的 v2 变量存储切片中的元素,循环中使用的这个变量 v2 会在每一次迭代被重新赋值而覆盖,赋值时也会触发拷贝。
func main() {
arr := []int{1, 2, 3}
newArr := []*int{}
for _, v := range arr {
newArr = append(newArr, &v)
}
for _, v := range newArr {
fmt.Println(*v)
}
}
$ go run main.go
3 3 3
总结:
for-range会被编译器翻译成普通的for循环,其中会进行一些优化。
for-range在同时遍历索引和元素的时候,会将创建一个临时变量存储元素,而且会复用(即不断往上赋值),这里我们的&v
始终是同一个地址
for _, v := range arr {
newArr = append(newArr, &v)
}
哈希表在遍历时会随机选中一个桶进行遍历,随后遍历所有溢出桶,最后按索引依次遍历哈希表中的其他桶。