// 创建一个字符串切片
// 其长度和容量都是 5 个元素
slice := make([]string, 5)

// 创建一个整型切片
// 其长度为 3 个元素,容量为 5 个元素,容量小于长度的切片会编译出错
slice := make([]int, 3, 5)
slice := []int{10, 20, 30}
// 使用空字符串初始化第 100 个元素
slice := []string{99: ""}

// 创建 nil 整型切片
var slice []int
slice := make([]int, 0)
slice := []int{}

如果在[]运算符里指定了一个值,那么创建的就是数组而不是切片。只有不指定值 的时候,才会创建切片

切片的使用

// 其长度和容量都是 5 个元素
slice := []int{10, 20, 30, 40, 50}

// 其长度为 2 个元素,容量为 4 个元素,该切片不能看见底层数组第0号元素
newSlice := slice[1:3]

// 使用原有的容量来分配一个新元素
// 将新元素赋值为 60
newSlice = append(newSlice, 60)

因为 newSlice 在底层数组里还有额外的容量可用,append 操作将可用的元素合并到切片 的长度,并对其进行赋值。由于和原始的 slice 共享同一个底层数组,slice 中索引为 3 的元 素的值也被改动了

如果切片的底层数组没有足够的可用容量,append 函数会创建一个新的底层数组,将被引用的现有的值复制到新数组里,再追加新的值

综上:创建切片的时候尽量使长度和容量一致,如果增加append新值是新开一个底层数组,而不是直接修改

e.g:
    source := []int{0, 1, 2, 3}
    slice1 := source[0:3]
    fmt.Println(slice1)
    // [0 1 2]
    slice2 := append(slice1, 100)
    slice2[0] = 99
    fmt.Println(slice1)
    fmt.Println(slice2)
    // [99 1 2]
    // [99 1 2 100]

迭代切片
slice := []int{10, 20, 30, 40}
// 迭代每一个元素,并显示其值
for index, value := range slice {
    fmt.Printf("Index: %d Value: %d\n", index, value)
}
如果需要忽略index值,使用下划线占位
当迭代切片时,关键字 range 会返回两个值。第一个值是当前迭代到的索引位置,第二个 值是该位置对应元素值的一份副本
slice := []int{10, 20, 30, 40}
for index, value := range slice {
    // 输出值和地址
    fmt.Printf("Value: %d Value-Addr: %X ElemAddr: %X\n",
        value, &value, &slice[index])
}

//第二种迭代方式
for index := 0; index < len(slice); index++ {
    fmt.Printf("Index: %d Value: %d\n", index, slice[index])
}
关键字 range 总是会从切片头部开始迭代。如果想对迭代做更多的控制,依旧可以使用传 统的 for 循环

多维切片

// 创建一个整型切片的切片
slice := [][]int{{10}, {100, 200}}
// 为第一个切片追加值为 20 的元素
slice[0] = append(slice[0], 20

切片属于引用类型,在函数间传递开销很小

举例理解切片和底层数组

// 长度为3, 容量为5
slice1 := make([]int, 3, 5)   // 修改5为3,创建一个长度与容量一致的切片
// 切片所有默认值都是0
slice1[1] = 1
slice1[2] = 2
// 切片2与1共享一个底层数组
slice2 := slice1[0:3]
// 在切片2上面增加一个数据
slice3 := append(slice2, 200)
// 在切片1上面增加一个数据
slice4 := append(slice1, 100)
fmt.Println(slice1) // [0, 1, 2]
fmt.Println(slice2) // [0, 1, 2]
fmt.Println(slice3) // [0, 1, 2, 100]
fmt.Println(slice4) // [0, 1, 2, 100]
再次说明:内置函数 append 会首先使用可用容量。一旦没有可用容量,会分配一个 新的底层数组。这导致很容易忘记切片间正在共享同一个底层数组。一旦发生这种情况,对切片 进行修改,很可能会导致随机且奇怪的问题。对切片内容的修改会影响多个切片,却很难找到问 题的原因。