golang切片
目录
特性
- 简化版的动态数组 这是切片类型的灵魂
- 必须初始化后,才能使用
- 切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。
- 操作切片,会影响原切片
- 切片和数组差距就是声明的时候没有长度
- 切片的底层就是一个数组
数据内存结构
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
x := []int{2,3,5,7,11} 和 y := x[1:3]
切片定义方式
var (
a []int // nil 切片, 和 nil 相等, 一般用来表示一个不存在的切片
b = []int{} // 空切片, 和 nil 不相等, 一般用来表示一个空的集合
c = []int{1, 2, 3} // 3个元素的切片 len cap 都为3
d = c[:2] // 有 2 个元素的切片, len 为 2, cap 为 3
e = c[0:2:cap(c)] // 有 2 个元素的切片, len 为 2, cap 为 3
f = c[:0] // 有 0 个元素的切片, len 为 0, cap 为 3
g = make([]int, 3) // 有 3 个元素的切片, len 和 cap 都为 3
h = make([]int, 2, 3) // 有 2 个元素的切片, len 为 2, cap 为 3
i = make([]int, 0, 3) // 有 0 个元素的切片, len 为 0, cap 为 3
)
添加切片
内置的泛型函数 append 可以在切片的尾部追加 N 个元素
var a []int
a = append(a, 1) // 追加一个元素
fmt.Println(a) // [1]
a = append(a, 1, 2, 3) // 追加多个元素,手写解包方式
fmt.Println(a) // [1 1 2 3]
a = append(a, []int{1, 2, 3}...) // 追加一个切片,切片需要解包
fmt.Println(a) // [1 1 2 3 1 2 3]
var b []int
b = append([]int{1}, b...) // 开头 追加一个元素,会导致内存的重新分配,开销大!!!!
fmt.Println(b) // [1]
删除切片
- a = a[:len(a)-N] 删除尾部 N 个元素
- a = a[N:] 删除开头 N 个元素
- a = append(a[:i], a[i+N:]...) // 删除中间 N 个元素
var c = []int{1, 2, 3}
c = c[:len(c)-1] // 删除最后一个元素
fmt.Println(c) // [1 2]
var d = []int{1, 2, 3}
d = d[1:] // 删除开头 1 个元素
fmt.Println(d) // [2 3]
var f = []int{1, 2, 3, 4, 5}
f = append(f[:2], f[3:]...)
fmt.Println(f) // [1 2 4 5]
内存泄漏
slice底层是数组,比如一个很大的数组,但是所取的slice元素很小,这样内存就会被浪费
示例一
问题:如果传入的slice b是很大的,然后引用很小部分给全局量a,
那么b未被引用的部分(下标1之后的数据)就不会被释放,造成了所谓的内存泄漏
// 内存泄漏问题一、
func test(b []int) {
num_big := b[:1] // 和b共用一个底层数组
fmt.Println(num_big)
return
}
// 解决方案
func test_ok(b []int) {
num_big := make([]int, 1)
copy(num_big, b[:1])
return
}
示例二
问题:返回的slice是很小一部分,这样该函数退出后,原来那个体积较大的底层数组也无法被回收
// 内存泄漏问题二、
func test2() []int {
a1 := make([]int, 1000000)
for i := 0; i < 1000000; i++ {
a1 = append(a1, i)
}
return a1[100:102]
}
// 解决方法
func test2_ok() []int {
a1 := make([]int, 1000000)
for i := 0; i < 1000000; i++ {
a1 = append(a1, i)
}
a2 := make([]int, 1)
copy(a2, a1[100:102])
return a2
}
切片内存技巧
- 切片高效操作的要点是要降低内存分配的次数