Golang 切片
切片( slice ),是对数组的抽象。 // 数组长度固定、不可改变,在一些特定场景中,这种集合并不实用
// 数组求和 func arraySum(arr [3]int) int { // 这个求和函数只能接收 [3]int 类型,其他的类型都不支持 sum := 0 for _, v := range arr { sum += v } return sum } func main() { // 数组 arr 中只能有三个元素,不能再添加新元素了 arr := [3]int{1, 2, 3} result := arraySum(arr) fmt.Println(result) // 6 }Then,Golong 提供了一种灵活、功能强悍的内置类型:切片( 可以简单理解为:一个未指定大小的( 动态 )数组 )
- len() 函数:切片是可索引的,可以由 len() 方法获取长度
- cap() 函数:切片,提供了计算容量的方法 cap(),可以测量切片最长可以达到多少
与数组相比,切片的长度是不固定的,可以追加元素( 追加元素时,可能使切片的容量增大,支持自动扩容 )
另,切片,是一个引用类型,进行函数传参时,传递的是引用
切片的声明与初始化
(1)声明
// 方式1:常规声明 var identifier []type var slice []int // 切片不需要说明长度 fmt.Println(slice) // [],切片在未初始化之前默认为 nil,长度为 0 // 方式2:使用make函数来创建切片:make([]T, length, capacity) var slice1 []int = make([]int, 3) // length,是数组的长度,也是切片的初始长度 slice2 := make([]int, 3, 10) // 也可以指明容量( 可选 ) fmt.Println(slice1) // [0 0 0] fmt.Println(len(slice1), cap(slice1)) // 切片的长度为3,容量为3 fmt.Println(slice2) // [0 0 0] fmt.Println(len(slice2), cap(slice2)) // 切片的长度为3,容量为10
(2)切片的初始化
//(1)直接初始化
slice3 := []int{1, 2, 3}
fmt.Println(slice3) // [1 2 3]
//(2)arr[:] 通过引用数组,初始化切片
arr4 := [...]int{1, 2, 3, 4, 5}
slice4 := arr4[:]
fmt.Println(slice4) // [1 2 3 4 5]
// arr[startIndex:endIndex] 从数组的下标[startIndex,endIndex)进行引用,创建一个新的切片
// arr[startIndex:] 默认 endIndex,表示一直到 arr 的最后一个元素
// arr[:endIndex] 默认 startIndex,表示从 arr 的第一个元素开始
slice5 := arr4[1:4]
fmt.Println(slice5) // [2 3 4]
// (3)通过引用切片,初始化切片
slice6 := slice5[1:]
fmt.Println(slice6) // [3 4]
切片的使用
「 切片的长度和容量 」切片拥有自己的长度和容量 // 切片的扩容策略
- 可以使用内置函数 len() ,求切片的长度
- 可以使用内置函数 cap() ,求切片的容量
slice1 := []int{1, 2, 3, 4, 5} fmt.Println(len(slice1)) // 5 fmt.Println(cap(slice1)) // 5 slice2 := make([]int, 3, 10) fmt.Println(len(slice2)) // 3 fmt.Println(cap(slice2)) // 10
「 切片截取 」 // 切片的本质 & 切片表达式( a[low:high] )
slice7 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 初始化一个切片
fmt.Println(slice7) // 原始切片 [0 1 2 3 4 5 6 7 8 9]
fmt.Println(slice7[1:5]) // 截取切片索引[1-5) [1 2 3 4]
fmt.Println(slice7[:5]) // 截取索引从开始到5 [0 1 2 3 4]
fmt.Println(slice7[5:]) // 截取索引从5到最后 [5 6 7 8 9]
fmt.Println(slice7) // 截取后,生成了新的切片,对原切片没什么影响 [0 1 2 3 4 5 6 7 8 9]
「 为切片添加元素 」可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素( 后面加… )
slice8 := append(slice7, 10) fmt.Println(slice8) // 追加一个切片元素 [0 1 2 3 4 5 6 7 8 9 10] fmt.Println(len(slice7), cap(slice7)) // 切片长度 10,切片容量 10 fmt.Println(len(slice8), cap(slice8)) // 追加了一个元素,切片长度 11,切片容量是之前的两倍 slice8 = append(slice8, 11, 12, 13, 14, 15) fmt.Println(slice8) // 追加多个切片元素 a := []int{1, 2, 3, 4, 5} b := []int{6, 7, 8, 9} c := append(a, b...) // 可以添加另一个切片中的元素( 后面加… ) fmt.Println(c) // [1 2 3 4 5 6 7 8 9]「 从切片中删除元素 」Golang 中,并没有删除切片元素的专用方法,可以利用切片本身的特性来操作
// 从切片 x 中删除索引为 index 的元素,操作方法是 x = append(x[:index], x[index+1:]...) x := []int{1, 2, 3, 4, 5, 6} fmt.Println(x) // [1 2 3 4 5 6] // 需求:删除索引为 2 的元素,即,值 3 x = append(x[:2], x[3:]...) fmt.Println(x) // [1 2 4 5 6]
「 拷贝切片 」copy 函数,是将一个切片的数据,复制到另外一个切片空间中
slice9 := []int{1, 2, 3, 4, 5}
fmt.Println(slice9) // [1 2 3 4 5]
// 方式1:直接赋值,赋值的是引用,修改拷贝后的切片,会影响原切片
var slice10 []int // 声明slice10
slice10 = slice9
fmt.Println(slice10)
slice10[0] = 100
fmt.Println(slice10) // [100 2 3 4 5]
fmt.Println(slice9) // [100 2 3 4 5]
// 方式2:引用切片,修改拷贝后的切片,也会影响原切片
slice9 = []int{1, 2, 3, 4, 5} // 重新初始化 [1 2 3 4 5]
slice11 := slice9[:]
fmt.Println(slice11) // [1 2 3 4 5]
slice11[0] = 20
fmt.Println(slice11) // [20 2 3 4 5]
fmt.Println(slice9) // [20 2 3 4 5]
// 方式3:copy 函数:将一个切片的数据,复制到另外一个切片空间中
slice9 = []int{1, 2, 3, 4, 5} // 重新初始化 [1 2 3 4 5]
var slice12 []int
copy(slice12, slice9)
fmt.Println(slice12) // [],因为slice12为空,没有空间接收slice9
slice13 := make([]int, 3, 10) // 初始长度为3,最大容量为10
copy(slice13, slice9)
fmt.Println(slice13) // [1 2 3] 空间不足,则只接收能接收的
slice14 := make([]int, 7)
copy(slice14, slice9)
fmt.Println(slice14) // [1 2 3 4 5 0 0] 空间足够
「 反转切片 」切片,是一个引用类型,进行函数参数传递时,传递的是引用
func main() {
slice15 := []int{1, 2, 3, 4, 5}
// 通过指针传递(推荐),会影响原有切片
slice16 := rev(&slice15)
fmt.Println(slice15) // [5 4 3 2 1]
fmt.Println(slice16) // [5 4 3 2 1]
// 当然,也可以传递一个值 rev(slice15),这样,也会对原切片产生影响,对rev函数做相应类型调整即可
// 切片,是一个引用类型,所以,进行函数参数传递时,传递的是引用 ?!
slice15 = []int{1, 2, 3, 4, 5}
fmt.Println(slice15) // [1 2 3 4 5]
slice17 := revFunc(slice15)
fmt.Println(slice15) // [5 4 3 2 1]
fmt.Println(slice17) // [5 4 3 2 1]
}
// 反转切片(指针形式)
func rev(slice *[]int) []int {
fmt.Println(*slice) // [1 2 3 4 5]
for i, j := 0, len(*slice)-1; i < j; i, j = i+1, j-1 {
(*slice)[i], (*slice)[j] = (*slice)[j], (*slice)[i]
}
return *slice
}
// 反转切片(值形式)
func revFunc(slice []int) []int {
fmt.Println(slice)
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
slice[i], slice[j] = slice[j], slice[i]
}
return slice
}