Slice 简介
- 切片是一个拥有相同类型元素可变长度的集合,数组是不可变长的集合。切片相对数组来说更加的灵活,可追加元素,自动扩容。
- 它可理解为可变长度的数组,可以看作动态“数组”。
包含三个字段。如图所示:
这3个字段分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)。Slice 切片的定义与初始化
// 方法一:使用var关键字声明 var sliceExample []string // 方法二:使用make方法 var sliceExample = make([]string, 1) // 方法三:方法二的简化 sliceExample := make([]string, 1) // 方法四:直接初始化 var sliceExample = []string{"1", "2", "3"} // 方法五:方法四简化 sliceExample := []string{"1", "2", "3"}
初始化时给出所需的长度和容量作为索引,最后一个元素设置为指定的元素,如下所示:
//创建11个元素的切片,第11个元素值为:第十一个元素 sliceExample := []string{10: "第十一个元素"} fmt.Println("值:", sliceExample, "长度len:", len(sliceExample), "容量cap:", cap(sliceExample))
注意: GoLang不允许定义容量小于长度的切片
// 初始化一个切片
sliceExample := make([]int, 61, 5)
使用数组初始化切片
// 创建数组
var arr = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 从索引1(包含索引1)的位置开始,到索引3(不包含索引3)
var sliceZero = arr[1:3]
// 从索引1(包含索引1)的位置开始,到尾部所有,相当于删除索引为1的元素
var sliceOne = arr[1:]
// 从索引0(包含索引0)的位置开始,到索引2(不包含2)结束
var sliceTwo = arr[:2]
// 把arr所有元素都赋值给sliceThree
var sliceThree = arr[:]
// 从索引0(包含索引0)的位置开始,到arr长度-1的位置结束, 相当于删除最后一个元素
var sliceFour = arr[:len(arr)-1]
fmt.Println("sliceZero: ", sliceZero)
fmt.Println("sliceOne: ", sliceOne)
fmt.Println("sliceTwo: ", sliceTwo)
fmt.Println("sliceThree: ", sliceThree)
fmt.Println("sliceFour: ", sliceFour)
// 修改 sliceFour[0] 元素值
sliceFour[0] = 100
fmt.Println(sliceFour)
fmt.Println("sliceZero: ", sliceZero)
fmt.Println("sliceOne: ", sliceOne)
fmt.Println("sliceTwo: ", sliceTwo)
fmt.Println("sliceThree: ", sliceThree)
fmt.Println("sliceFour: ", sliceFour)
从上面可以看到, 修改了 sliceFour[0] 的元素值,sliceTwo,sliceThree,sliceFour值也跟着修改了;我们看一个更具体的例子:
var a = []int{1, 3, 4, 5}
fmt.Printf("slice a : %v , len(a) : %v\n", a, len(a))
b := a[1:2]
fmt.Printf("slice b : %v , len(b) : %v\n", b, len(b))
c := b[0:3]
fmt.Printf("slice c : %v , len(c) : %v\n", c, len(c))
可能会好奇为什么是这样? 原因是上面操作的为底层a, 我们看一下这张图:
nil和空切片
nil切片
创建nil切片, 只需要在声明切片的时候不初始化就可以了,如下所示:// 创建nil切片 var nilSlice []int if nilSlice == nil { fmt.Println("nilSlice为一个nil切片") }
使用场景:
(1). 函数要求返回一个切片但是发生异常的时候;
(2). 描述一个不存在的切片时,nil切片会很好用;
(3). nil 切片可以用于很多标准库和内置函数
nil切片的状态:
空切片
方法1:// 创建空切片 emptySlice := []int{} if emptySlice == nil { fmt.Println("emptySlice为一个nil切片") } else if len(emptySlice) == 0 { fmt.Println("emptySlice是一个空切片: len", len(emptySlice), "cap:", cap(emptySlice)) }
方法2:
// 创建空切片 emptySlice := make([]int, 0) if emptySlice == nil { fmt.Println("emptySlice为一个nil切片") } else if len(emptySlice) == 0 { fmt.Println("emptySlice是一个空切片: len", len(emptySlice), "cap:", cap(emptySlice)) }
空切片的状态:
不管是使用 nil 切片还是空切片,对其调用内置函数 append()、len() 和 cap() 的效果都是一样的。
获取切片的长度和容量
len():当前切片个有多少个元素
cap():底层元素个数,通俗得讲:切片总共能存放多少个元素
// 初始化一个切片
sliceExample := make([]string, 0, 10)
fmt.Println("填充之前的切片", sliceExample, "length:", len(sliceExample), "cap", cap(sliceExample))
切片的赋值
初始化一个nil切片,使用下标赋值时会报错(panic: runtime error: index out of range [0] with length 0),
// 创建一个nil切片 var emptySlice []int // 覆盖下标为0的元素值 emptySlice[0] = 26 fmt.Println(emptySlice)
注意:此时使用 emptySlice = append(emptySlice, 1) 添加元素使用下标覆盖切片元素
// 创建切片,并对其进行初始化 emptySlice := []int{2, 3, 4, 5} // 覆盖下标为0的元素值 emptySlice[0] = 26 fmt.Println(emptySlice)
使用append添加元素
使用append()函数为切片动态添加元素时,如果空间不够容纳足够多的元素,就会进行扩容,此时切片的长度会发生变化。// 声明一个切片 var sliceExample []string // 单次追加单个元素 sliceExample = append(sliceExample, "PHP") // 单词追加多个元素 sliceExample = append(sliceExample, "Java", "JavaScript", "Rust") fmt.Println(sliceExample)
我们初始化了一个切片,容量为10,向里面填充11个元素,因为超过了容量,此时切片被扩容了。
// 初始化一个切片
sliceExample := make([]string, 0, 10)
// 填充元素
for i := 0; i <= 10; i++ {
sliceExample = append(sliceExample, "PHP")
}
fmt.Println("填充之后的切片", sliceExample, "length:", len(sliceExample), "cap:", cap(sliceExample))
切片读取
使用下标进行访问
// 初始化一个切片
sliceExample := make([]string, 0, 10)
// 填充元素
sliceExample = append(sliceExample, "GoLang")
// 直接使用下标进行访问
fmt.Println(sliceExample[0])
循环遍历
// 初始化一个切片
sliceExample := make([]string, 0, 10)
// 填充元素
for i := 0; i <= 10; i++ {
sliceExample = append(sliceExample, "PHP")
}
// 对切片进行遍历
for index, value := range sliceExample {
fmt.Println("下标:", index, "value:", value)
}
切片元素的删除
1. 从起始位置开始删除
a = a[N:] // 删除开头N个元素, 这样删除会重置下标
// 初始化一个切片
sliceExample := []int{1, 2}
fmt.Println("删除之前的元素:")
for index, value := range sliceExample {
fmt.Println("index:", index, "value:", value)
}
// 从切片起始位置删除一个元素
sliceExample = sliceExample[1:]
fmt.Println("删除之后的元素:")
for index, value := range sliceExample {
fmt.Println("index:", index, "value:", value)
}
2. 从起始位置开始删除
a = a[:N] // 从尾部删除个元素
// 初始化一个切片
sliceExample := []int{1, 2, 3}
fmt.Println("删除之前的元素:")
for index, value := range sliceExample {
fmt.Println("index:", index, "value:", value)
}
// 从尾部删除1一个元素
sliceExample = sliceExample[:len(sliceExample)-1]
fmt.Println("删除之后的元素:")
for index, value := range sliceExample {
fmt.Println("index:", index, "value:", value)
}
从切片中间删除删除
// 我们初始化一个数组, 然后删除掉中间的6
var arr = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice := append(arr[:5], arr[6:]...)
fmt.Println(slice)
结论:
删除中间1个元素:
slice = append(a[:i], a[i+1:]...)
删除中间N个元素:
slice = append(a[:i], a[i+N:]...)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。