Go中的切片Slice

1,846 阅读3分钟

Go中的切片Slice

切片概念

切片是一种数据结构, 是一种动态数组, 按需自动改变大小, 可以方便的管理和使用数据集合

内部实现

  1. 切片基于数组实现的, 切片的底层是数组。
  2. 切片本身非常小, 是对数组的抽象
  3. 因为切片基于数组实现的, 所以底层的内存是连续分配的, 效率非常高
  4. 切片可以通过索引获得数据, 可以迭代以及垃圾回收优化
  5. 切片是对数组view的映射, 公用底层数组, 改变切片就会改变底层数组

切片声明和初始化

声明

  • make方法, 单独参数, 既指定长度也指定容量

  • // 长度和容量都是5
        slice := make([]int, 5)
    
  • make方法, 两个参数, 指定长度和容量

  • // 长度为5, 容量为10(容量对应底层数组)
    slice := make([]int, 5, 10)
    
    
    1. 切片的底层为数组, 切片不指定值默认为零值
    2. 切片长度为5, 容量为10, 所以只能访问5个值
    3. 剩下5个元素需要切片扩充后才能访问
    4. 切片的容量必须 >= 切片的长度
  • 使用:=创建切片

    // 此时切片的长度和容量都是5
      slice:=[]int{1,2,3,4,5}
    
  • 使用:=创建部分切片

    // 此时切片的长度和容量都是5
    slice:=[]int{4:1}
    
  • 数组和切片的区别

    //数组
    array:=[5]int{4:1}
    //切片
    slice:=[]int{4:1}
    
  • nil切片和空切片的区别, 他们的长度和容量都是0, 指向的底层数组不同

    • nil切片指向底层数组的指针为nil, 表示不存在的切片
    • 空切片指向的底层数组为指针为地址, 表示空切片集合
    //nil切片
    var nilSlice []int
    //空切片
    slice:=[]int{}
    

基于现有的数组或者切片创建切片

  1. 使用[i:j]来创建新的切片, i为索引开始, j为索引结束, 半开半闭区间, 包含i, 不包含j
  2. i 和 j 都可省略, 省略后默认为 0 和 len(slice) - 1
  3. 对于数组或者切片(容量为k)创建新的切片(slice[i:j])后的长度和容量为 长度为j - i, 容量为k - i
  4. 系统内置方法长度为len(slice), 容量为cap(slice)

使用第三个值来限制切片容量

  1. 创建了一个长度为 2 - 1 = 1, 容量为3 - 1 = 2
  2. 第三个值不能超过原切片容量的最大值
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:2:3]

向切片追加值

  1. 通过append方法向切片追加值
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:3]

newSlice=append(newSlice,10)
fmt.Println(newSlice)
fmt.Println(slice)
//Output
[2 3 10]
[1 2 3 10 5]
  1. 通过append同时追加许多值
newSlice=append(newSlice,10,20,30)
  1. 通过...append向切片中追加切片
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:2:3]

newSlice = append(newSlice, slice...)
  1. append函数会智能的增长底层数组的容量,目前的算法是:容量小于1000个时,总是成倍的增长,一旦容量超过1000个,增长因子设为1.25,也就是说每次会增加25%的容量。

迭代切片

  1. 使用for range迭代切片
slice := []int{1, 2, 3, 4, 5}
for i,v:=range slice{
	fmt.Printf("索引:%d,值:%d\n",i,v)
}
  1. 也可以使用for迭代切片
slice := []int{1, 2, 3, 4, 5}
for i := 0; i < len(slice); i++ {
	fmt.Printf("值:%d\n", slice[i])
}

注意点

  1. range返回的是切片元素的复制, 不是元素的引用

在函数中传递切片

func main() {
	slice := []int{1, 2, 3, 4, 5}
	fmt.Printf("%p\n", &slice)
	modify(slice)
	fmt.Println(slice)
}
func modify(slice []int) {
	fmt.Printf("%p\n", &slice)
	slice[1] = 10
}

注意点

  1. 传递复制切片时, 底层数组不会被复制, 也不会收影响, 复制只是复制的切片本身, 不涉及底层数组