Go语言还未入门就放弃之切片slice

内部实现

对数组进行抽象封装,可以动态增长,类似C++里面的vector。切片有 3 个字段的数据结构。分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)

声明和初始化

  • slice := make([]string, 5) 创建一个字符串切片,其长度和容量都是 5 个元素。如果只指定长度,那么切片的容量和长度相等
  • slice := make([]int, 3, 5) 创建一个整型切片,其长度为 3 个元素,容量为 5 个元素。无法创建一个长度大于容量的切片
  • slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"} 通过切片字面量来声明切片,长度和容量都是 5 个元素
  • slice := []string{99: "hello"} 使用索引声明切片,使用字符串”hello”初始化第 100 个元素。长度,容量均为 100
  • var slice []int 创建 nil 整型切片,长度,容量均为 0
  • slice := make([]int, 0) 声明空切片。注意,不管是nil切片还是空切片,均可进行内置函数 append、 len 和 cap 的操作。跟其他语言不一样,nil切片也是可以追加元素的。

使用切片

  • slice[1] = 25 改变索引为 1 的元素的值
  • 使用切片创建切片
    1
    2
    slice := []int{10, 20, 30, 40, 50} // 创建一个整型切片,其长度和容量都是 5 个元素
    newSlice := slice[1:3] // 创建一个新切片,其长度为 2 个元素,容量为 4 个元素。注意,区间是左闭右开,所以newSlice最终值位[20, 30]。

推广开来,对底层数组容量是 cap 的切片 slice[i:j]来说,那么长度为 j - i,容量: cap - i。注意:使用切片创建的切片由于会共享底层的数组,所以此时修改新的切片会影响原来的切片。当然,在某些情况下,如果在一个slice中添加新的数据,在原有数组无法保持更多新的数据时,将导致分配一个新的数组。而现在其他的slice还指向老的数组(和老的数据),这时修改新的切片对原有的切片不会有影响。

  • 使用 append 向切片增加元素,内置函数 append 也是一个可变参数的函数。这意味着可以在一次调用传递多个追加的值。可以使用…运算符将一个切片的所有元素追加到另一个切片里

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 创建一个整型切片
    // 其长度和容量都是 5 个元素
    slice := []int{10, 20, 30, 40, 50}
    // 创建一个新切片
    // 其长度为 2 个元素,容量为 4 个元素
    newSlice := slice[1:3]
    // 使用原有的容量来分配一个新元素
    // 将新元素赋值为 60
    newSlice = append(newSlice, 60)

    slice2 := []int{0}
    slice2 = append(slice2, slice...)

    // slice -> {10, 20, 30, 60, 50} 由于共享底层数组,注意这个第 4 个元素变成了60
    // newSlice -> {20, 30, 60}
    // slice2 -> {0, 10, 20, 30, 60, 50}
  • slice := source[2:3:4] 使用 3 个索引创建切片。推广开来,对于 slice[i:j:k],长度len = j - i,容量cap = k - i。注意:如果试图设置的容量比可用的容量还大,就会得到一个语言运行时错误。

多维切片

  • slice := [][]int{ {10}, {100, 200} } 创建一个整型切片的切片

在函数间传递切片

在64位机器上,一个切片需要 24 字节的内存:指针字段需要 8 字节,长度和容量字段分别需要 8 字节。所以只需要传递 24 字节。

1
2
3
4
5
// 函数 foo 接收一个整型切片,并返回这个切片
func foo(slice []int) []int {
//...
return slice
}

切片的遍历

  • 传统for循环

    1
    2
    3
    for i := 0; i<len(slice); i++ {
    fmt.Println(array1[i])
    }
  • range表达式。注意:range 创建了每个元素的副本,而不是直接返回对该元素的引用,即改变value的值不会改变切片里面的内容。

    1
    2
    3
    for i, value := range slice {
    fmt.Println(i, value)
    }
您的支持将鼓励我继续创作!
0%