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
}

切片内存技巧

  • 切片高效操作的要点是要降低内存分配的次数
posted @ 2023-01-10 17:28  半截肥皂  阅读(470)  评论(0编辑  收藏  举报