数组是一片连续的内存。slice
则是一个结构体,包含三个字段:长度 len
、容量 cap
、底层数组
。
// runtime/slice.go
type slice struct {
array unsafe.Pointer // 元素指针
len int // 长度
cap int // 容量
}
slice
的生命周期围绕着按 cap
预先分配 底层数组
及 cap
不足时重新分配 cap*2
的 底层数组
。
特别要注意的时,当我们使用下标范围
来得到 子切片
时,子切片
和 父切片
指向的 底层数组
在此时是 同一片内存地址
。后续 子切片
可能会因为 容量cap
不足而重新申请容量时,从 父切片
的 底层数组
中独立出来。
package main
import (
"fmt"
)
func main() {
slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := slice[2:5] //len3 cap8
s2 := s1[2:6:7] //len4 cap5
fmt.Println(s1, len(s1), cap(s1))
fmt.Println(s2, len(s2), cap(s2))
fmt.Println(strings.Repeat("=", 10))
//s2的容量已满 如果后续再追加成员,将重新分配一套底层数组
s2 = append(s2, 100)
//s1和s2还在公用一套底层数组 s1[2] == s2[0]
s1[2] = 20
fmt.Println(s1, len(s1), cap(s1))
fmt.Println(s2, len(s2), cap(s2))
fmt.Println(strings.Repeat("=", 10))
//s2的重新分配底层数组 容量扩充为原来的2倍=5*2
s2 = append(s2, 200)
//s1与s2的底层数组已不同 s1[2] 已无法影响 s2[0]
s1[2] = 200
fmt.Println(s1, len(s1), cap(s1))
fmt.Println(s2, len(s2), cap(s2))
}
只有当子切片的 容量cap
不足,重新申请分配新的容量内存段时,才会从父切片的底层数组中独立查出来。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。