对于所有的 range 循环,Go 语言都会在编译期将原切片或者数组赋值给一个新变量 ha,在赋值的过程中就发生了拷贝,而我们又通过 len 关键字预先获取了切片的长度,所以在循环中追加新的元素也不会改变循环执行的次数,这也就解释了循环永动机一节提到的现象。
    而遇到这种同时遍历索引和元素的 range 循环时,Go 语言会额外创建一个新的 v2 变量存储切片中的元素,循环中使用的这个变量 v2 会在每一次迭代被重新赋值而覆盖,赋值时也会触发拷贝

    1. func main() {
    2. arr := []int{1, 2, 3}
    3. newArr := []*int{}
    4. for _, v := range arr {
    5. newArr = append(newArr, &v)
    6. }
    7. for _, v := range newArr {
    8. fmt.Println(*v)
    9. }
    10. }
    11. $ go run main.go
    12. 3 3 3

    总结:
    for-range会被编译器翻译成普通的for循环,其中会进行一些优化。

    for-range在同时遍历索引和元素的时候,会将创建一个临时变量存储元素,而且会复用(即不断往上赋值),这里我们的&v始终是同一个地址

    1. for _, v := range arr {
    2. newArr = append(newArr, &v)
    3. }

    哈希表在遍历时会随机选中一个桶进行遍历,随后遍历所有溢出桶,最后按索引依次遍历哈希表中的其他桶。