2023-03-01 19:10:23
Go 语言中的切片(slice)是一种动态数组,其底层实现涉及指针、长度和容量。以下是关于 Go 切片的详细解析:
底层结构:切片由三个字段组成:
array:指向底层数组的指针。
len:切片的当前长度,可通过 len() 函数获取。
cap:切片的最大容量,即在不扩容的情况下最多能容纳的元素数量,可通过 cap() 函数获取。
创建方式:
var 声明:创建一个值为 nil 的切片,此时 array 为空指针,len 和 cap 均为 0。
字面量:直接指定所有元素,此时 len 和 cap 等于元素个数。
make 函数:可指定长度和容量,格式为 make([]type, len[, cap])。
切片操作符:从现有数组或切片中切取一部分,格式为 [low:high],注意区间是左闭右开的。
添加元素:
使用 append() 函数向切片添加元素。如果剩余空间足够,则直接添加;否则,进行扩容,分配更大的数组空间,复制旧元素后再添加。
常见问题:
空切片与 nil 的关系:
var s1 []uint32 创建的切片等于 nil。
s2 := make([]uint32, 0) 创建的切片不等于 nil,因为 make() 为其分配了空间。
传值还是传引用:
切片传递的是 runtime.slice 结构的值,但底层数组是共享的。因此,修改切片元素会影响所有共享该数组的切片。
扩容策略:
当前容量小于 1024 时,扩容为原来的 2 倍;大于等于 1024 时,逐次增加 0.25 倍,直到满足需求。
字符串切片:
切片操作符可以切取字符串,但返回的是字符串而非切片,因为字符串是不可变的。
底层数据共享:
使用切片操作符时,若上界超过原切片的长度但未超过容量,新切片会与原切片共享底层数组的部分数据,可能导致意外修改。Go 1.2 引入了 [low:high:max] 语法来限制新切片的容量,避免此问题。
总结:
理解切片的底层结构有助于避免常见误区。
切片传递的是结构体的值,但底层数组是共享的,需注意数据修改的影响。
使用 append() 时应接收返回值,以更新切片的 array、len 和 cap 字段。
扩容策略和切片操作符的使用需谨慎,以避免不必要的性能开销或数据覆盖问题。
通过掌握这些细节,可以更高效、安全地使用 Go 切片。