赞
踩
目录
切片(slice)是Golang中数组之上的抽象;可按需自动增长与缩小。切片的底层是连续的内存块。
切片本身是一个三个字段的数据结构:
- type SliceHeader struct {
- Data uintptr
- Len int
- Cap int
- }
有多种创建切片的方式。
内置的make函数可用于创建切片(长度不能超过容量):
- // 创建长度为0,容量为10的切片
- s := make([]int, 0, 10)
-
- // 创建长度为10(存储的是对应类型的默认值,即0),容量为10的切片
- s2 := make([]int, 10)
-
- // 获取底层对应数据结构
- low:=(*reflect.SliceHeader)(unsafe.Pointer(&s1))
- fmt.Printf("Data:%d,Len:%d,Cap:%d\n",low.Data,low.Len,low.Cap)
根据给定的数据,自动创建并初始化切片(与数组的区别是[]中没有长度信息):
- // 长度、容量都为3的切片
- s := []int{1,2,3}
-
- // 长度、容量都为10,最后一个元素为99,其他为默认值0
- s2 := []int{9: 99}
声明时不做任何初始化就会创建一个nil切片;而空切片是底层数组包含0个元素,且没有分配存储空间。nil与空切片都可直接获取长度(len)或追加元素(append)。
- // 值为nil的切片
- var s []int
-
- // 创建空切片
- s1 := make([]int, 0)
- s2 := []int{}
在已有数组/切片上创建切片为:s = src[low : high : max] ,三个参数意义为
在已有数组/切片上切出一部分可以生成新的切片,他们共享底层的数组;因此修改一个切片的内容(在不扩容的情况下),会影响到其他共享底层数组的切片:
- // 元素范围为[i,j),k限制容量为(k-i)
- s := src[i:j:k]
-
- // 从i到尾部
- s := src[i:]
-
- // 从头到j(不包括j)
- s := src[:j]
-
- // 从头到尾(复制整个切片),但底层数组还是公用的
- s := src[:]
切片只能访问其长度范围内的内容,通过下标访问
- s[i] = 10
- v = s[i]
切片是一个集合,可以通过range迭代其中的元素:
- for index, value := range myS{
- fmt.Printf("index: %d, value: %d\n", index, value)
- }
range返回的第二个值是对应元素的一份副本,不能用于修改;若要修改则需要通过索引:
- for index, _ := range myS{
- myS[index] += 1
- }
迭代方式遍历时,不能有其他线程对切片进行操作(添加、或删除元素),否则会引发恐慌。
切片可直接传递给‘不定参数’,即使空切片也可以:
- func NilSliceParam() {
- var s []string
- multiEle(s...)
- }
-
- func multiEle(all ...string) {
- log.Println(all)
- }
通过函数append可在切片尾部追加元素;通过copy(dest,src)可复制切片,复制的长度是minimum of len(src) and len(dst)。
可对nil切片追加元素,以及求长度:
- var sl []int // nil
- if sl == nil{ // true
- fmt.Println("is nill")
- }
- fmt.Println(sl) // []
- fmt.Println(len(sl)) // 0
- sl = append(sl, 1) // [1]
Slice依托数组实现,底层数组容量不足时可自动重新分配。追加数据通过append(返回值一定要再赋值给原slice);容量不足时会自动扩容:
- var s []int // s == nil
- fmt.Println(s) // []
- fmt.Println(len(s)) // 0
- for i := 0; i < 5; i++ {
- s = append(s, i+1)
- }
- // 容量:0,1,2,4,8
在插入元素时,若空间不足则会自动重新分配新的空间:
- a = append(a, 1, 2, 3)
- a = append(a, []int{1,2,3}...) // 追加切片时,需要使用...解包
头部插入时,会引起内存的分配与复制操作:
- // 即使一个元素,也要以切片的形式插入
- a = append([]int{1}, a...)
- a = append([]int{1,2,3}, a...)
在中间(i)插入元素:
- a = append(a, x...) // 先扩展出足够的空间
- copy(a[i+len(x):], a[i:]) // 后移len(x)个元素,空出空间
- copy(a[i:], x)
从切片中删除的元素若是指针(特别是尾部删除时,可能还会被底层数组引用中,从而无法被gc回收);为了能及时的释放,在需要在删除前,先把对应元素设置为nil再删除;
- a[len(a)-1]=nil
- a = a[:len(a)-1]
删除尾部N个元素:
a = a[:len(a)-N]
删除头部元素有两种方式:
- // 删除头部N个元素,改变数据指针
- a = a[N:]
-
- // 删除切片头部元素,不改变数据指针:
- a = append(a[:0], a[N:]...) // 在头部追加剩余元素
- a = a[:copy(a, a[N:])] // 复制元素都头部,然后修改切片长度
删除切片中间部分元素:
- // 方法1:append追加,覆盖被删除元素
- a = append(a[:i], a[i+N:]...)
-
- // 方法2:复制,覆盖被删除元素
- a = a[:i+copy(a[i:], a[i+N:])]
要在遍历时删除,就不能用range迭代的方式:
- func removeAllLessEle(queueMax []int, ele int) []int {
- // pop all ele less than ele
- for j := 0; j < len(queueMax); {
- if queueMax[j] < ele {
- queueMax = append(queueMax[:j], queueMax[j+1:]...)
- } else{
- j = j + 1
- }
- }
- return queueMax
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。