一、切片(Slice)
@author:韩茹
版权所有:北京千锋互联科技有限公司
1.1 什么是切片 Go 语言切片是对数组的抽象。 Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大
切片是一种方便、灵活且强大的包装器。切片本身没有任何数据。它们只是对现有数组的引用。
切片与数组相比,不需要设定长度,在[]中不用设定值,相对来说比较自由
从概念上面来说slice像一个结构体,这个结构体包含了三个元素:
指针,指向数组中slice指定的开始位置
长度,即slice的长度
最大长度,也就是slice开始位置到数组的最后位置的长度
1.2 切片的语法 定义切片
切片不需要说明长度。 或使用make()函数来创建切片:
1 2 3 var slice1 []type = make ([]type , len )也可以简写为 slice1 := make ([]type , len )
1 make ([]T, length, capacity)
初始化
1 2 3 s[0 ] = 1 s[1 ] = 2 s[2 ] = 3
1 s := arr[startIndex:endIndex]
将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片(前闭后开 ),长度为endIndex-startIndex
缺省endIndex时将表示一直到arr的最后一个元素
缺省startIndex时将表示从arr的第一个元素开始
1 2 3 4 5 6 7 8 9 10 11 package mainimport ( "fmt" ) func main () { a := [5 ]int {76 , 77 , 78 , 79 , 80 } var b []int = a[1 :4 ] fmt.Println(b) }
1.3 修改切片 slice没有自己的任何数据。它只是底层数组的一个表示。对slice所做的任何修改都将反映在底层数组中。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "fmt" ) func main () { darr := [...]int {57 , 89 , 90 , 82 , 100 , 78 , 67 , 69 , 59 } dslice := darr[2 :5 ] fmt.Println("array before" ,darr) for i := range dslice { dslice[i]++ } fmt.Println("array after" ,darr) }
运行结果:
1 2 array before [57 89 90 82 100 78 67 69 59] array after [57 89 91 83 101 78 67 69 59]
当多个片共享相同的底层数组时,每个元素所做的更改将在数组中反映出来。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport ( "fmt" ) func main () { numa := [3 ]int {78 , 79 ,80 } nums1 := numa[:] nums2 := numa[:] fmt.Println("array before change 1" ,numa) nums1[0 ] = 100 fmt.Println("array after modification to slice nums1" , numa) nums2[1 ] = 101 fmt.Println("array after modification to slice nums2" , numa) }
运行结果:
1 2 3 array before change 1 [78 79 80] array after modification to slice nums1 [100 79 80] array after modification to slice nums2 [100 101 80]
1.4 len() 和 cap() 函数 切片的长度是切片中元素的数量。切片的容量是从创建切片的索引开始的底层数组中元素的数量。
切片是可索引的,并且可以由 len() 方法获取长度 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少
1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport "fmt" func main () { var numbers = make ([]int ,3 ,5 ) printSlice(numbers) } func printSlice (x []int ) { fmt.Printf("len=%d cap=%d slice=%v\n" ,len (x),cap (x),x) }
运行结果
1 len =3 cap =5 slice=[0 0 0 ]
空切片
一个切片在未初始化之前默认为 nil,长度为 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport "fmt" func main () { var numbers []int printSlice(numbers) if (numbers == nil ){ fmt.Printf("切片是空的" ) } } func printSlice (x []int ) { fmt.Printf("len=%d cap=%d slice=%v\n" ,len (x),cap (x),x) }
运行结果
1 2 len =0 cap =0 slice=[]切片是空的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport "fmt" func main () { numbers := []int {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 } printSlice(numbers) fmt.Println("numbers ==" , numbers) fmt.Println("numbers[1:4] ==" , numbers[1 :4 ]) fmt.Println("numbers[:3] ==" , numbers[:3 ]) fmt.Println("numbers[4:] ==" , numbers[4 :]) numbers1 := make ([]int ,0 ,5 ) printSlice(numbers1) number2 := numbers[:2 ] printSlice(number2) number3 := numbers[2 :5 ] printSlice(number3) } func printSlice (x []int ) { fmt.Printf("len=%d cap=%d slice=%v\n" ,len (x),cap (x),x) }
运行结果
1 2 3 4 5 6 7 8 len =9 cap =9 slice=[0 1 2 3 4 5 6 7 8 ]numbers == [0 1 2 3 4 5 6 7 8 ] numbers[1 :4 ] == [1 2 3 ] numbers[:3 ] == [0 1 2 ] numbers[4 :] == [4 5 6 7 8 ] len =0 cap =5 slice=[]len =2 cap =9 slice=[0 1 ]len =3 cap =7 slice=[2 3 4 ]
1.5 append() 和 copy() 函数 append 向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice copy 函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数
append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。 但当slice中没有剩 余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原 数组的内容将保持不变;其它引用此数组的slice则不受影响
下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package mainimport "fmt" func main () { var numbers []int printSlice(numbers) numbers = append (numbers, 0 ) printSlice(numbers) numbers = append (numbers, 1 ) printSlice(numbers) numbers = append (numbers, 2 ,3 ,4 ) printSlice(numbers) numbers1 := make ([]int , len (numbers), (cap (numbers))*2 ) copy (numbers1,numbers) printSlice(numbers1) } func printSlice (x []int ) { fmt.Printf("len=%d cap=%d slice=%v\n" ,len (x),cap (x),x) }
运行结果
1 2 3 4 5 len =0 cap =0 slice=[]len =1 cap =2 slice=[0 ]len =2 cap =2 slice=[0 1 ]len =5 cap =8 slice=[0 1 2 3 4 ]len =5 cap =12 slice=[0 1 2 3 4 ]
numbers1与numbers两者不存在联系,numbers发生变化时,numbers1是不会随着变化的。也就是说copy方法是不会建立两个切片的联系的
千锋Go语言的学习群:784190273
作者B站:
https://space.bilibili.com/353694001
对应视频地址:
https://www.bilibili.com/video/av56018934
https://www.bilibili.com/video/av47467197
源代码:
https://github.com/rubyhan1314/go_foundation