package main

import "fmt"

func main() {
    a := [3]int{0, 1, 2}
    fmt.Printf("遍历前第一个元素内存地址:%p\n", &a[0])
    fmt.Printf("遍历前第二个元素内存地址:%p\n", &a[1])
    fmt.Printf("遍历前第三个元素内存地址:%p\n", &a[2])
    for i, v := range a {
        fmt.Printf("遍历中元素内存地址:%p\n", &v)
        if i == 0 {
            a[1], a[2] = 999, 999 //直接对底层进行修改
            fmt.Println(a)        //修改成功
        }
        a[i] = v + 100 //v是复制品,值分别是0,1,2
    }
    fmt.Println(a)
}
  • 输出如下:
遍历前第一个元素内存地址:0xc00001a1f8
遍历前第二个元素内存地址:0xc00001a200
遍历前第三个元素内存地址:0xc00001a208
遍历中元素内存地址:0xc00001e0d8
[0 999 999]
遍历中元素内存地址:0xc00001e0d8
遍历中元素内存地址:0xc00001e0d8
[100 101 102]

总结需要注意的点:
1、在遍历时,获取的值地址相比遍历前已发生变化,且在遍历时获取的值的地址唯一。
2、在遍历时,有且只有一个变量副本。
3、通过下标访问能直接修改数组中的元素。

range for array底层实现:
1、遍历前获取数组的长度作为循环次数,在循环体中,每次循环会先获取元素值,如果for-range中接收index和value的话,会对index和value进行一次赋值,所以要尽量避免对大元素进行遍历而影响性能,因为大量赋值会产生gc。
2、在遍历开始前循环次数就已经确定了,所以循环过程中新添加的元素是不可能遍历到的。
3、数组指针和slice的遍历过程与数组基本一致。