切片数据结构

  1. // runtime/slice.go
  2. type slice struct {
  3. array unsafe.Pointer // 元素指针
  4. len int // 长度
  5. cap int // 容量
  6. }

切片的内存模型

  1. func main() {
  2. arr := [5]int{1, 3, 5, 6, 7}
  3. fmt.Printf("addr:%p\n", &arr)// addr:0xc42001a1e0
  4. s1 := arr[:]
  5. fmt.Printf("addr:%p\n", &s1)// addr:0xc42000a060
  6. changeSlice(s1)
  7. }
  8. func changeSlice(s []int) {
  9. fmt.Printf("addr:%p\n", &s)// addr:0xc42000a080
  10. fmt.Printf("addr:%p\n", &s[0])// addr:0xc42001a1e0
  11. }

代码中定义了一个数组 arr,然后用它生成了一个slice。如果go中存在引用传递,形参 s 的地址应该与实参 s1 一样(上面c++的证明),通过实际的情况我们发现它们具备完全不同的地址,也就是传参依然发生了拷贝——值传递。

但是这里有个奇怪的现象,大家看到了 arr 的地址与 s[0] 有相同的地址,这也就是为什么我们在函数内部能够修改 slice 的原因,因为当它作为参数传入函数时,虽然 slice 本身是值拷贝,但是它内部引用了对应数组的结构,因此 s[0] 就是 arr[0] 的引用,这也就是能够进行修改的原因。

切片内存模型 - 图1