复习一下切片,slice

例子

demo1

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7} //数组
	s := arr[2:6]  //从数组取2—6
	fmt.Println(s) //输出 [2 3 4 5]
    fmt.Println(arr[:6]) // [0 1 2 3 4 5] 省略头直接从0开始
	fmt.Println(arr[2:])   // [2 3 4 5 6 7] 省略尾巴直接到末尾
	fmt.Println(arr[:])  // [0 1 2 3 4 5 6 7]  头尾都省了全部都有
}

demo2

slice不是一个值类型,是数据结构视图
arr[:6] 是对于 arr的一个视图
[]int 表示一个slice 没有...或者长度,与数组区别

func updateSlice(s []int) {
	s[0] = 100
}

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:] //[2 3 4 5 6 7]

	fmt.Println(s1) //	修改前  [2 3 4 5 6 7]
	updateSlice(s1) //执行修改
	fmt.Println(s1) //[100 3 4 5 6 7]  //切片0的位置改为了100
	fmt.Println(arr) //[0 1 100 3 4 5 6 7]  原来数组的相应位置2 也被改成了100
}

因为s1作为arr的一个切片,算是一个视图,所以s1改动时候影响到arr数组的相应位置也发生改动
貌似用来修改数组是个好方案,省得用指针改
总结:slice本身没有数据,slice是对底层array的一个视图

demo3

reslice 在slice上面建立slice

func main() {
   arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
   s2 := arr[:] //取得arr全部
   fmt.Println(s2) //[0 1 2 3 4 5 6 7]

   s2 = s2[:5] //在s2上面取开始到5
   fmt.Println(s2) //[0 1 2 3 4]

   s2 = s2[2:] //在去过开始到5基础上的s2 上面再取2到结束
   fmt.Println(s2) //[2 3 4]

}

可以在一个底层array上面建立多个slice
可以在slice基础上再建立slice,但是底层还是同一个array

demo3

extending slice 拓展slice

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6] 
	fmt.Println(s1) //[2 3 4 5]

	s2 := s1[3:5]  //在s1基础上取 3,4 但是实际上最后就只有第3位指向的5,而没有4指向的(直接打印s1[4]都会报错
	fmt.Println(s2) //[5 6]  //结果取到了5 6,⚠️但是6压根不在s1里面

}

s2在s1上面取,然后取到了并不在s1中的数据,超出的数据实际上是底层arr的数据——切片的推展
slice下面有 ptr len cap只要不超过 cap就可以拓展 cap是底层的array slice可以向后扩展,不可以向前扩展 s[i] 不可以超过len(s),向后扩展不可以超过底层数组 cap(s)`

demo4

len和cap

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6]
	fmt.Printf("%v,%d,%d", s1, len(s1), cap(s1)) //[2 3 4 5],4,6 len就是4,cap就是6(还可以往后拓展到 [6 7]
}

len就是当前视图slice切片容量,cap就是向后可以拓展到底层array数组的容量

demo5

向slice append操作

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s2 := arr[5:7]                       //[5 6]
	s3 := append(s2, 10)                 //[5 6 10]
	s4 := append(s3, 11)                 //[5 6 10 11]
	s5 := append(s4, 12)                 // [5 6 10 11 12]
	fmt.Println("s3,s4,s5=", s3, s4, s5) //s3,s4,s5= [5 6 10] [5 6 10 11] [5 6 10 11 12]
	fmt.Println("arr=", arr) //arr= [0 1 2 3 4 5 6 10] //即使上面加到了12,但是最多对原来的底层arr影响也在10,没有超过容量
}

即使上面slice数据加到了12,但是最多对原来的底层arr影响也在10,没有超过arr容量。而11,12这些实际上进入到了一个新开的array里面(容量比原来的要大)——> s4,s5的slice已经不再是arr为底层array,由系统分配了一个新的array作为底层
添加元素时超过cap,系统会重新分配更大的底层数组,并且复制原来的值
原来的arr数组如果有用会被留下,没有用会被垃圾回收机制回收掉
由于值传递的关系,必须接收append的返回值
也就是类似 s = append(s,val)

demo6

demo6-1

创建slice 空的nil的 slice

func printSlice(s []int) {
	fmt.Printf("len=%d,cap=%d\n", len(s), cap(s))
}
func main() {
	var s []int

	for i := 0; i < 5; i++ {
		printSlice(s)
		s = append(s, 2*i+1)
	}
	fmt.Println(s)
}

输出

len=0,cap=0
len=1,cap=1
len=2,cap=2
len=3,cap=4
len=4,cap=4
[1 3 5 7 9]

demo6-2

:= []int创建

func main() {
	s1 := []int{2, 4, 6, 8}
	printSlice_c(s1) //len=4,cap=4
}

demo6-3

make 知道slice容量,但是不知道里面的值

func main() {
	s1 := make([]int, 16)
	s2 := make([]int, 10, 32)
	printSlice_d(s1) //len=16,cap=16
	printSlice_d(s2) //len=10,cap=32
}

demo7

复制copy slice

func main() {
	s1 := []int{1, 2, 3, 4} //[1 2 3 4]
	s2 := make([]int, 8)    //[0 0 0 0 0 0 0 0]
	copy(s2, s1) //把s1的值复制到s2
	fmt.Println(s2) //[1 2 3 4 0 0 0 0]

}

copy(复制到的位置,用于复制的数据)

###demo8

删除中间slice的值

func main() {
	s1 := []int{1, 2, 3, 4, 5, 0, 0, 0}
	fmt.Println(s1) //[1 2 3 4 5 0 0 0]

	s1 = append(s1[:3], s1[4:]...) //删除了4
	fmt.Println(s1) //[1 2 3 5 0 0 0]
}

由于没有给删除值的函数,所以用append来处理
s1[4:]...中的...表示把4以后的值全部往前面挪

删除首尾slice的值

func main() {
   s1 := []int{1, 2, 3, 4, 5, 0, 0, 0}
   fmt.Println(s1) //[1 2 3 4 5 0 0 0]

   //删除头
   front := s1[0] //1
   s1 = s1[1:]
   
   //删除尾
   tail := s1[len(s1)-1] //0
   s1 = s1[:len(s1)-1]

   fmt.Println(front, tail) //1 0
   fmt.Println(s1)     //[2 3 4 5 0 0]
}

删除头就把 [1:] 的值赋给原来的slice
删除尾就把 [:len(s)-1] 的值赋给原来的slice
删除会改变 len,不会改变 cap

完结撒花🎉