1.四种声明方式示例代码

slice.go

package chapter09

import "fmt"

// Run
func Run() {
    // 方式1:声明slice1 是一个切片,并且初始化,默认值是1,2,3,长度是3
    slice1 := []int{1, 2, 3}
    fmt.Printf("len = %d, slice1 = %v\n", len(slice1), slice1)

    // 方式2:声明slice2一个切片,但是并没有给slice2分配空间
    var slice2 []int
    slice2 = make([]int, 3) // 通过make开辟3个空间,默认值是0

    slice2[0] = 100
    fmt.Printf("len = %d, slice2 = %v\n", len(slice2), slice2)

    // 方式3:声明slice3一个切片,同时给slice3分配空间,3个空间,默认值是0
    var slice3 []int = make([]int, 3) // 通过make开辟3个空间,默认值是0

    fmt.Printf("len = %d, slice3 = %v\n", len(slice3), slice3)

    // 方式4:声明slice4一个切片,同时给slice4分配空间,3个空间,默认值是0,通过 := 推导出 slice4是一个切片
    slice4 := make([]int, 3) // 通过make开辟3个空间,默认值是0

    fmt.Printf("len = %d, slice4 = %v\n", len(slice4), slice4)

    // 判断一个切片是否为0
    var slice5 []int
    if len(slice5) == 0 {
        // if slice5 == nil {
        fmt.Println("slice5 是一个空切片")
    } else {
        fmt.Println("slice5 是有空间的")
    }
}

slice_test.go

package chapter09

import "testing"

func TestRun(t *testing.T) {
    Run()
}

执行结果

=== RUN   TestRun
len = 3, slice1 = [1 2 3]
len = 3, slice2 = [100 0 0]
len = 3, slice3 = [0 0 0]
len = 3, slice4 = [0 0 0]
slice5 是一个空切片
--- PASS: TestRun (0.00s)
PASS
ok      

2.切片的追加操作

2.1.示例代码

slice2.go

package chapter09

import "fmt"

func Run2() {
    var numbers = make([]int, 3, 5) // 声明 长度为3 ,容量为5的 int 切片

    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)

    // 向 numbers 切片追加一个元素 1, numbers len = 4, [0,0,0,1], cap = 5
    numbers = append(numbers, 1)
    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)

    // 向 numbers 切片追加一个元素 1, numbers len = 5, [0,0,0,1.2], cap = 5
    numbers = append(numbers, 2)
    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)

    // 向一个容量cap已经满的slice 追加元素
    numbers = append(numbers, 3)
    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)

    fmt.Println("----------")
    var numbers2 = make([]int, 3)
    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers2), cap(numbers2), numbers2)
    numbers2 = append(numbers2, 1)
    fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers2), cap(numbers2), numbers2)

}

执行结果

=== RUN   TestRun2
len = 3, cap = 5, slice = [0 0 0]
len = 4, cap = 5, slice = [0 0 0 1]
len = 5, cap = 5, slice = [0 0 0 1 2]
len = 6, cap = 10, slice = [0 0 0 1 2 3]
----------
len = 3, cap = 3, slice = [0 0 0]
len = 4, cap = 6, slice = [0 0 0 1]
--- PASS: TestRun2 (0.00s)
PASS
ok      

图示解说

12.slice切片声明、截取操作_Go
12.slice切片声明、截取操作_内存地址_02
12.slice切片声明、截取操作_赋值_03

动态开辟空间之前
12.slice切片声明、截取操作_默认值_04

动态开辟空间之后
12.slice切片声明、截取操作_示例代码_05

2.2.总结

12.slice切片声明、截取操作_示例代码_06

3.切片的截取操作

示例代码

slice3.go

package chapter09

import "fmt"

func Run3() {
    s := []int{1, 2, 3} // len = 3 , cap = 3 , [1, 2, 3]

    // [0,2)
    s1 := s[0:2] // [1, 2]
    fmt.Println(s1)

    s1[0] = 100

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

    // copy 可以将底层数组的slice一起进行拷贝
    s2 := make([]int, 3) // s2 = [0, 0, 0]

    // 将s中的值,依次拷贝到s2中
    copy(s2, s)

    fmt.Println("s2 = ", s2)
}

执行结果

=== RUN   TestRun3
[1 2]
s =  [100 2 3]
s1 =  [100 2 3]
s2 =  [100 2 3]
--- PASS: TestRun3 (0.00s)
PASS
ok  

copy的图示
copy前
12.slice切片声明、截取操作_赋值_07

copy后
12.slice切片声明、截取操作_内存地址_08

4.总结

  • 切片的声明(四种方式)
    • 方式1: slice1 := []int{1, 2, 3} , 声明+赋值操作
    • 方式2: var slice2 []int
      slice2 = make([]int, 3)
      声明和空间分配相互独立,采用make进行切片空间分配
    • 方式3:var slice3 []int = make([]int, 3) 简化方式2
    • 方式4:slice4 := make([]int, 3) , 使用的是类型推导的方式
  • 切片的追加
    • 如果声明了容量,追加元素后,切片的长度未达到容量的大小,不进行扩容;但是到达容量阈值时,进行2倍的方式进行扩容。
    • 如果没有指定容量,追加元素,长度到达容量阈值容量,进行2倍的形式扩容。
  • 切片的截取
    • 截取的切片指针与元切片共享一个内存地址
    • copy 是 为切片,从新开辟新的内存地址