切片
Go语言切片是一种建立在数组类型之上的抽象,它构建在数组之上并且提供更强大的能力和便捷。解决了数组长度不可变等缺陷
声明切片
切片的数据结构非常小,只有三个字段:指向底层数组的指针,切片长度,切片容量。切片长度是指切片的真实长度,切片容量是指切片的开始位置到底层数组的末尾的长度,一般来讲切片长度要小于等于底层数组的长度也就是切片容量
cap()
用来计算切片容量,len()
用来计算切片长度,所以有0 <= len() <= cap()
var 切片名 + [] + 数据类型
(声明切片但不初始化,那么这个切片的默认值为nil,长度为 0)
var slice []int
slice := make([]数据类型,切片长度,切片容量)
(使用make()来声明切片)
// 声明一个长度为10,容量为20的切片slice
slice := make([]int, 10, 20)
// 因为切片长度为10 所以只能访问10个元素,剩下的10个需要进行切片扩容之后才能使用
slice := []数据类型{初始化}
// 声明时初始化
slice := []int{0,1,2,3,4,5,6,7,8,9}
// 同数组一样,切片也可以对单一元素赋值
slice := []int{3:9,5:10}
- 基于现有的数组或切片,创建切片
// 创建底层数组array
array := [10]int{0,1,2,3,4,5,6,7,8,9}
// 以array 为底层数组创建切片slice,切片从索引3开始到索引9结束(并不包括索引9)
slice := array[3,9]
// 输出slice的长度和容量
fmt.Printf("切片长度:%d\n", len(slice)) // 6
fmt.Printf("切片容量:%d\n", cap(slice)) // 7
// slice := array[i,j]
// 切片长度(j-i):9 - 3 = 6
// 切片容量(底层数组长度 - i):10 - 3 = 7
// 也可以直接限制切片容量
slice := array[2,9,7]
fmt.Printf("切片长度:%d\n", len(slice)) // 7
fmt.Printf("切片容量:%d\n", cap(slice)) // 7
切片使用
使用切片,和使用数组一样,通过索引就可以获取切片对应元素的值,同样也可以修改对应元素的值
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:9]
slice[3] = 100
fmt.Println(arr) // [0 1 2 3 4 5 100 7 8 9]
⭐:因为切片是对部分底层数组的引用,所以修改切片的值,实际上是修改切片对应底层数组的值
遍历切片(for range)
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:9]
// i:切片下标 j: 下标对应的值
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
扩展切片
直接扩展
slice = slice[0 : len(slice)+1]
切片可以反复扩展直到占据整个相关数组,但是不能超过相关数组长度!!!!!
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:8]
fmt.Printf("slice长度:%d\n", len(slice))// 5
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
slice = slice[0 : len(slice)+1]
fmt.Printf("slice长度:%d\n", len(slice))// 6
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
append扩展
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := range arr {
fmt.Printf("arr[%d]: %p\n", i, &arr[i])
}// 0xc0000ac0f0 ~~ 0xc0000ac138
// 在以arr为底层数组创建切片slice,切片内元素的地址与数组内元素地址相同
slice := arr[3:9]
fmt.Printf("slice长度:%d\n", len(slice))// 6
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i := range slice {
fmt.Printf("slice[%d]: %p\n", i, &slice[i])
}// 0xc0000ac108 ~~ 0xc0000ac130
// 使用append()在arr后面扩展一位,保持切片长度仍小于切片容量,切片内元素的地址与数组内元素地址依旧相同,切片长度加一,切片容量不变
newSlice1 := append(slice, 9)
fmt.Printf("newSlice1长度:%d\n", len(newSlice1))// 7
fmt.Printf("newSlice1容量:%d\n", cap(newSlice1))// 7
for i := range newSlice1 {
fmt.Printf("newSlice1[%d]: %p\n", i, &newSlice1[i])
}// 0xc0000ac108 ~~ 0xc0000ac138
// 使用append()在arr后面扩展三位,导致切片长度大于原来的切片容量,切片内元素的地址与数组内元素地址完全不同,切片长度加三,切片容量翻倍
newSlice2 := append(slice, 9, 10, 11)
fmt.Printf("newSlice2长度:%d\n", len(newSlice2))// 9
fmt.Printf("newSlice2容量:%d\n", cap(newSlice2))// 14
for i := range newSlice2 {
fmt.Printf("newSlice2[%d]: %p\n", i, &newSlice2[i])
}// 0xc0000d4000 ~~ 0xc0000d4040
⭐:当切片扩展时,切片长度大于原切片的切片容量,就会新建一个底层数组,把原来数组的值复制到新底层数组里,再追加新值,这时候就不会影响原来的底层数组了。append
函数会智能的增长底层数组的容量,目前的算法是:容量小于1000个时,总是成倍的增长,一旦容量超过1000个,增长因子设为1.25,也就是说每次会增加25%的容量
文章评论