切片是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型
实际开发中我们很少使用数组,取而代之的是切片
切片是一个长度可变的数组
创建切片
使用语法 a[start:end] 创建一个从 a 数组索引 start 开始到 end - 1 结束的切片。
创建一个有3个 整型元素的数组,并返回存储在一个c中的切片引用
e := []int{6, 7, 8}
fmt.Println(e)
切片的修改
切片自己不拥有任何数据。
它只是底层数组的一种表示,对切片的任何修改都会反映在底层数组中
切片的长度和容量
切片的长度是切片中的元素数
切片的容量是从创建切片索引开始的底层数组中的元素
==切片可以重置其容量。==任何超出这一点将导致程序运行时抛出错误。//什么意思?
使用make创建一个切片
func make([]T,len,cap)[]T 通过传递类型,长度和容量来创建切片。容量是可选参数, 默认值为切片长度。make 函数创建一个数组,并返回引用该数组的切片。
追加切片元素
有一个问题可能会困扰你。如果切片由数组支持,并且数组本身的长度是固定的,那么切片如何具有动态长度。以及内部发生了什么,当新的元素被添加到切片时,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回这个新数组的新切片引用。现在新切片的容量是旧切片的两倍。
切片的函数传递
可以认为切片在内部由结构类型表示
type slice struct {
Length int
Capacity int
ZerothElement *byte
}
切片包含长度、容量和指向数组第零元素的指针。当切片传递给函数时,即使它是按值传递的,指针变量也会引用同一个底层数组。因此,当切片作为参数传递给函数时,函数内部所做的更改在函数外部也可见。让我们编写一个程序来检查一下。
对于函数中一个数组的变化在函数外是不可见的
package main
import (
"fmt"
)
func subtactOne(numbers []int) {
for i := range numbers {
numbers[i] -= 2
}
}
func main() {
nos := []int{8, 7, 6}
fmt.Println("slice before function call", nos)
subtactOne(nos)
fmt.Println("slice after function call", nos)
}
slice before function call [8 7 6]
slice after function call [6 5 4]
多维切片
package main
import (
"fmt"
)
func main() {
pls := [][]string {
{"C", "C++"},
{"Java"},
{"Go", "Rust"},
}
for _, v1 := range pls {
for _, v2 := range v1 {
fmt.Printf("%s ", v2)
}
fmt.Printf("\n")
}
}