赞
踩
Slice称为动态数组或切片,底层是数组实现,实际使用比数组更加灵活,可以方便地进行扩容和传递。
var s []int // 变量声明
s1 := []int{} // 空切片
s2 := []int{1,2,3}
s1 := make([]int,12) // 指定长度
s2 := make([]int,10,20) // 指定长度和容量
s3 := *new([]int) // 空切片
切片可以基于其他数组或切片创建,且与原数组和切片共享底层空间,修改切片会影响原数组或切片。
slice := a[low:high]
其中切片长度等于 high - low,容量长度等于底层数组的长度,其中 low 和 high 可以省略。
这种表达式存在两个问题
// 情况一
/* 代码 */
a := [5]int{1, 2, 3, 4, 5}
aSlice := a[1:2] // 前闭后开,取下标为1的位置,即 2 = a[1]
fmt.Println("aSlice:", aSlice, " aSliceLen:", len(aSlice), " aSliceCap:", cap(aSlice)) // aSlice: [2] aSliceLen: 1 aSliceCap: 4
fmt.Println("a:", a) // a: [1 2 3 4 5]
aSlice = append(aSlice, 8) // 追加一个新元素
fmt.Println("aSlice:", aSlice, " aSliceLen:", len(aSlice), " aSliceCap:", cap(aSlice)) // aSlice: [2 8] aSliceLen: 2 aSliceCap: 4
fmt.Println("a:", a) // a: [1 2 8 4 5]
/* 控制台 */
aSlice: [2] aSliceLen: 1 aSliceCap: 4
a: [1 2 3 4 5]
aSlice: [2 8] aSliceLen: 2 aSliceCap: 4
a: [1 2 8 4 5] // a[2]位置已经从 3 -> 8
// 情况二
/* 代码 */
a := [5]int{1, 2, 3, 4, 5}
fmt.Println("a:", a)
aSlice := a[0:]
aSlice[0] = 2 // 修改下标0位置元素
fmt.Println("aSlice:", aSlice, " a:", a)
aSlice = append(aSlice, 9) // 简单表达式下 cap 到达数组极限,扩容后的切片将不再影响原数组
aSlice[0] = 5 // 修改下标0位置元素
fmt.Println("aSlice:", aSlice, " a:", a)
/* 控制台 */
原数组 a: [1 2 3 4 5]
aSlice: [2 2 3 4 5] a: [2 2 3 4 5] // 修改下标0位置后的 aSlice 和 a,此时切片影响了原数组
aSlice: [5 2 3 4 5 9] a: [2 2 3 4 5] // 触发扩容后的 aSlice 和数组,此时的修改操作对原数组没有影响,说明扩容产生的新切片底层数组已经不是原数组。
*边界问题:0 ≤ low ≤ high ≤ cap(a),否则触发 panic | 意味着 high 的取值可以大于 len(a) *
slice := a[low:high:max]
限制新切片容量的表达式,因为简单表达式可能会覆盖 a[high] 后的元素,产生意料之外的影响。
边界问题:0 ≤ low ≤ high ≤ max ≤ cap(a)
向切片追加元素。
当切片 len=cap 时,向切片追加元素会产生扩容,扩容后生成的新切片将不会影响原数组或切片。
扩容: 当切片容量不足时会重新申请内存空间更大的新切片,将原切片内容复制到新切片,最后追加元素。
扩容规则: ① Slice容量<1024时,申请两倍内存空间;② Slice容量≥1024时,申请1.25倍内存空间。
查询切片长度
查询切片容量
// src/runtime/slice.go:slice
type slice struct {
array unsafe.Pointer // 底层数组指针
len int // 切片长度
cap int // 切片容量
}
当切片很小,但底层数组占据了大量空余内存,该如何优化?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。