创建Slice
切片(Slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型).这个片段可以是整个数组.
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
a := arr[2:6]
fmt.Println("a =>", a) // a => [2 3 4 5]
a0 := arr[:6]
fmt.Println("a0 =>", a0) // a0 => [0 1 2 3 4 5]
a1 := arr[2:]
fmt.Println("a1 =>", a1) // a1 => [2 3 4 5 6 7]
a2 := arr[:]
fmt.Println("a2 =>", a2) // a2 => [0 1 2 3 4 5 6 7]
}
Slice属于半开半闭区间的,包头不包尾,:左右两边不写,相当于从下标0开始,到最后一个元素结束
slice作为参数
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
a1 := arr[2:]
fmt.Println("a1 =>", a1) // a1 => [2 3 4 5 6 7]
updateSlices(a1)
fmt.Println("arr =>", arr) // arr => [0 1 100 3 4 5 6 7]
}
func updateSlices(s []int){
s[0] = 100;
}
- go语言一般不会使用数组作为参数,大多数情况下都是使用切片
- Slice本身没有数据的,是对底层array的一个view.
- 对Slice中元素的修改会影响array的元素
Reslice
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
s := arr[2:]
fmt.Println("s =>",s) // s => [2 3 4 5 6 7]
s = s[:5]
fmt.Println("s =>",s) // s => [2 3 4 5 6]
s = s[:3]
fmt.Println("s =>",s) // s => [2 3 4]
}
- slice上面可以再建立slice
- 这些不同的slice都是view的同一个array
Slice的扩展
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
fmt.Println("s1 =>",s1) // s1 => [2 3 4 5]
s2 := s1[3:5]
fmt.Println("s2 =>",s2) // s2 => [5 6]
}
- s2把不属于s1的元素6也取出来了,说明Slice是可以进行扩展的,但是如果直接使用s1[4]还是会索引越界
Slice的实现
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
// s1 =[2 3 4 5], len(s1)=4, cap(s1)=6
fmt.Printf("s1 =%v, len(s1)=%d, cap(s1)=%d\n",s1,len(s1),cap(s1))//
s2 := s1[3:5]
// s2 =[5 6], len(s2)=2, cap(s2)=3
fmt.Printf("s2 =%v, len(s2)=%d, cap(s2)=%d\n",s2,len(s2),cap(s2))
// panic: runtime error: slice bounds out of range [:4] with capacity 3
fmt.Println(s2[:4])
}
-
Slice内部有三个变量
- ptr指向Slice开头的元素
- len是Slice的长度
- cap是代表ptr到整个array最后
-
Slice可以向后扩展,不可以向前扩展
-
s[i]不可以超过len(s),向后扩展不可以超越底层数组cap(s)
Slice的操作
append
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
// s1 =[2 3 4 5], len(s1)=4, cap(s1)=6
fmt.Printf("s1 =%v, len(s1)=%d, cap(s1)=%d\n", s1, len(s1), cap(s1))
s2 := s1[3:5]
// s2 =[5 6], len(s2)=2, cap(s2)=3
fmt.Printf("s2 =%v, len(s2)=%d, cap(s2)=%d\n", s2, len(s2), cap(s2))
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
fmt.Println("s3 =>", s3) // s3 => [5 6 10]
fmt.Println("s4 =>", s4) // s4 => [5 6 10 11]
fmt.Println("s5 =>", s5) // s5 => [5 6 10 11 12]
fmt.Println("arr =>", arr) // arr => [0 1 2 3 4 5 6 10]
}
- 添加元素时如果超越cap,系统会重新分配更大的底层数组(s4,s5不再是对arr的view,是系统分配更大的底层数组的view);原来的数组如果有引用,它就还在,如果没有引用就会被垃圾回收
- 由于值传递的关系,必须接收append的返回值
- s = append(s,val)
Slice的扩容
func printSlice(s []int){
fmt.Printf("len=%d,cap=%d\n",len(s),cap(s))
}
func main() {
var s [] int
fmt.Println(s)
for i:=0; i<10;i++{
printSlice(s)
s = append(s,i)
}
// [0 1 2 3 4 5 6 7 8 9]
fmt.Println(s)
}
//len=0,cap=0
//len=1,cap=1
//len=2,cap=2
//len=3,cap=4
//len=4,cap=4
//len=5,cap=8
//len=6,cap=8
//len=7,cap=8
//len=8,cap=8
//len=9,cap=16
当len为0时,cap也为0,当len开始添加元素时,cap从开始扩容为1,以后每次添加不了元素时都进行2倍的扩容
func main() {
s1 := []int{2,4,6,8}
// [2 4 6 8] len=4,cap=4
printSlice(s1)
s2 := make([]int,16)
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] len=16,cap=16
printSlice(s2)
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] len=16,cap=32
s3 := make([]int, 16, 32)
printSlice(s3)
}
func printSlice(s []int){
fmt.Printf("%v len=%d,cap=%d\n",s,len(s),cap(s))
}
CopySlice
func main() {
arr1 := []int{1,3,5,7,9}
arr2 :=make([]int,10);
// [0 0 0 0 0 0 0 0 0 0] len=10,cap=10
printSlice(arr2)
copy(arr2,arr1)
// [1 3 5 7 9 0 0 0 0 0] len=10,cap=10
printSlice(arr2)
}
func printSlice(s []int){
fmt.Printf("%v len=%d,cap=%d\n",s,len(s),cap(s))
}
删除元素
删除中间的元素
func main() {
arr1 := []int{1,3,5,7,9}
//[1 3 5 7 9] len=5,cap=5
printSlice(arr1)
arr1 = append(arr1[:1],arr1[2:]...)
//[1 5 7 9] len=4,cap=5
printSlice(arr1)
}
func printSlice(s []int){
fmt.Printf("%v len=%d,cap=%d\n",s,len(s),cap(s))
}
删除头元素
func main() {
arr1 := []int{1,3,5,7,9}
//[1 3 5 7 9] len=5,cap=5
printSlice(arr1)
head := arr1[0]
arr1 = arr1[1:]
//[3 5 7 9] len=4,cap=4
printSlice(arr1)
//head => 1
fmt.Println("head =>",head)
}
func printSlice(s []int){
fmt.Printf("%v len=%d,cap=%d\n",s,len(s),cap(s))
}
删除尾元素
func main() {
arr1 := []int{1,3,5,7,9}
//[1 3 5 7 9] len=5,cap=5
printSlice(arr1)
tail := arr1[len(arr1)-1]
arr1 = arr1[:len(arr1)-1]
//[1 3 5 7] len=4,cap=5
printSlice(arr1)
//tail => 9
fmt.Println("tail =>",tail)
}
func printSlice(s []int){
fmt.Printf("%v len=%d,cap=%d\n",s,len(s),cap(s))
}