切片(Slice)
数据结构
slice是一个动态数组,切片中的元素存放在一块内存地址连续的区域,使用索引可以快速检索到指定位置的元素,以下的数据结构也称为Slice Header。
1 | //package:Go SDK 1.22.0/src/runtime/slice.go |
- array:指向了内存空间地址的起始位置,slice数据存放在连续的内存空间中,根据索引 index,在起点的基础上进行地址偏移,从而定位到目标元素。
- len:slice的长度,指的是逻辑意义上,slice 中实际存放了多少个元素。
- cap:切片的容量,指的是物理意义上为slice分配了足够用于存放多少个元素的空间,cap永远大于等于len。
slice是引用传递还是值传递
引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
- 示例1:
1 | func Test_slice(t *testing.T){ |
在go语言中,只有值传递。在该例中,slice作为参数时,似乎变成了其他语言中引用传递的效果。
原因在于:方法间传递切片时,会对 slice header 实例本身进行一次值拷贝,然后将 slice header 的副本传递到局部方法中。这个 slice header 副本中的 array 和原 slice 指向同一片内存空间,所以效果为引用传递(但只会修改原有的数组长度的元素)。
- 示例2:
1 | func Test_slice(t *testing.T){ |
综上,slice作为参数在函数方法中时,由于传入了array的地址指针,对应的切片的长度内的元素被修改时,原数组会被修改,若发生扩容则不会影响原数组。
初始化
- 声明但不初始化
1 | var s []int |
s初始化时是一个空指针 nil,并没有完成实际的内存分配操作。
基于 make 进行初始化
- 指定len
1
s := make([]int,8)
将切片的长度 len 和 容量 cap 同时设置为 8,且初始元素均为0。
- 指定len和cap
1
s := make([]int,8, 16)
在切片中设置8个元素,初始元素均为0,需要保证 cap >= len。切访问[len, cap)的元素时会越界。
初始化连带赋值
1
s := []int{2,3,4}
slice 长度 len 和容量 cap 均设置为 3,同时完成对这 3 个元素赋值。
二维Slice
声明m行n列
1 | // 创建一个切片的切片,每个元素表示一行 |
参考
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.