一、切片概念

1. 基本例子

slice 是对数组的一个视图,且他是一个引用
package main

import "fmt"

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    fmt.Println(arr[2:6])
    fmt.Println(arr[:6])
    fmt.Println(arr[2:])
    fmt.Println(arr[:])
}

运行输出

$ go run 06slice.go
[2 3 4 5]
[0 1 2 3 4 5]
[2 3 4 5 6 7]
[0 1 2 3 4 5 6 7]

2. 引用的使用

package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100
}

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    s1 := arr[:]
    fmt.Println(s1)
    updateSlice(s1) // 传参是引用
    fmt.Println(s1)
    fmt.Println(arr) // 底层的数组也会改变

}

运行输出

$ go run 06slice.go
[0 1 2 3 4 5 6 7]
[100 1 2 3 4 5 6 7]
[100 1 2 3 4 5 6 7]

因为slice是引用类型,所以当执行updateSlice后,s1的值也发生了变化


3. reslice

package main

import "fmt"

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    s1 := arr[:]
    fmt.Println(s1)
    s1 = s1[:3] // 对slice 再slice
    fmt.Println(s1)
    s1 = s1[1:]
    fmt.Println(s1)
}

运行输出

$ go run 06slice.go
[0 1 2 3 4 5 6 7]
[0 1 2]
[1 2]

二、 扩展

ptr 指向开头的元素
cap 指的是容量(capacity

package main

import "fmt"

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}

    s1 := arr[2:6]
    s2 := s1[3:5]

    fmt.Println("arr = ", arr)
    fmt.Println("s1 = ", s1)
    fmt.Println("s2 = ", s2)

    fmt.Printf("s1=%v, len(s1)=%d, cap(s1)=%d\n", s1, len(s1), cap(s1))
    fmt.Printf("s2=%v, len(s2)=%d, cap(s2)=%d\n", s2, len(s2), cap(s2))
}

运行输出

$ go run 06slice.go
arr =  [0 1 2 3 4 5 6 7]
s1 =  [2 3 4 5]
s2 =  [5 6]
s1=[2 3 4 5], len(s1)=4, cap(s1)=6 // 因为是向后扩展cap是6,包含[2 3 4 5 6 7]
s2=[5 6], len(s2)=2, cap(s2)=3     // 向后扩展cap是3,包含[5 6 7]
  • slice 可以向后扩展,不可以向前扩展
  • s[i]不可以超过len(s),向后扩展不可以超越底层数组cap(s)

注意:当是向后扩展的时候,如下

fmt.Println(s1[:7])

s1[:7]中的7超过cap的最大值6,所以就报错了

slice bounds out of range [:7] with capacity 6

如果是通过下标直接获取slice的元素,这里就不能超过len的值了,下标是0开始,所以最大下标要减1

fmt.Println(s1[3])

三、添加元素

添加元素时如果超越cap,系统会重新分配更大的底层数组
package main

import "fmt"

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}

    s1 := arr[2:6]

    fmt.Println("arr = ", arr)
    fmt.Println("s1 = ", s1)

    s2 := append(s1, 10)
    s3 := append(s2, 11)
    s4 := append(s3, 12)

    fmt.Println()

    fmt.Println("s1 = ", s1)
    fmt.Println("s2 = ", s2)
    fmt.Println("s3 = ", s3)
    fmt.Println("s4 = ", s4)
    fmt.Println("arr = ", arr)
}

运行输出

$ go run 06slice.go
arr =  [0 1 2 3 4 5 6 7]
s1 =  [2 3 4 5]

s1 =  [2 3 4 5]
s2 =  [2 3 4 5 10]
s3 =  [2 3 4 5 10 11]
s4 =  [2 3 4 5 10 11 12]   // 注意:s4 的值有12
arr =  [0 1 2 3 4 5 10 11] // 注意:arr 追加到11这个元素后,没有12这个元素了

s4cap 已经超过了 arrcap,所以底层就复制了一个新的数组,s4是在新的数组上的一个view