slice切片
切片是数组的一部分,slice本身是数组的引用!!!
也就是说,如果修改slice的"数据",array数组本身也会变
切片声明
var arr [5]int //array
var slice []int //slice 没有长度的数组被称为切片,只是数组的引用,
我们举个例子:
接下来,我们对数组进行切片
比如说,我们想要数组中的5和8
为什么是1:3?因为是不包含结束位置的!
到slice里面是重新记录下标,但是在原数组中还是不变的
接下来,我们对切片的值进行修改看看,数组中对应的元素值也会变,因为切片是数组的引用!
slice切片的用途
1.方便操作——把数组其中的一段截取出来,然后用起来就方便,第0个,第1个…
2.传参——增强性能、方便修改原数组
我们再来做一些操作:
因为slice本身就是引用!
总结1
切片和数组是两种数据类型——互相不能直接赋值
切片本质上不是数组,只是对数组的引用。
下面这种写法是错误的
如果对整个数组都切片,然后赋值给数组,也是不可以的。
拓展提升1
切片也可以"脱离"数组
slice:=[]int{12,5,8}
//底层等价于下面这2个操作:还是和数组有关的
arr:=[3]int{12,5,8}
slice:=arr[0:3]
接下来,我们进行操作:
也可以这么写:
拓展提升2
slice初始化
1.直接给值
[]int{12,5,8}
2.空切片(不是真的空,而是空间被初始化为0)
make(类型, 个数, ?)//内置函数
下面这个初始化的写法是错误的:
数组不能丢给切片
正确的初始化如下:
切片都是一直和数组有关系,底层都是弄了一个数组,然后切完把切片给你
拓展提升3
在array数组中,len==cap
但是在slice切片中 len!=cap
我们看看这个切片的len和cap
len是指切片slice切出来的元素的个数
cap是指切片slice的容量,最大的上限
假设我们有一个原始数组,有5个元素
然后我们切片,取出第2个和第3个元素进行切片,只是arr和slice是映射关系哦
所以,从图中我们可以看出来,slice切片的最大容量是4个
slice是可以动态的重新声明的。
比如说,原本slice引用的是其中的2个,现在后悔了,还想要1个。
这个时候是不涉及到复制数据的操作, 直接给自己加1个就可以了。
拓展提升4
slice是可以动态给自身扩容的
array是是静态的如果array想要自身扩容只能修改源码->重新编译
array 编译期分配好了——性能非常高
slice 运行时分配 ——性能略差
如果把arr数组重新分配空间,下面写法是错误的:
下面这种写法也是错误的
new可以帮我们动态的创建数据:
但是还是不能帮我们把数组动态扩容的:
因为一开始分配的是5个大小空间,动态推测出来这个arr的类型是个指向5个数据的int类型的数组的指针
如果我们这么写,还是错误的:
arr数组是静态的,在编译完,就定死了
slice是可以动态给自身扩容的,slice 运行时分配,因为在声明的时候没有说明自己多长
最后总结
slice≈array
1.知道上限、性能要求高——array
2.无法预测、性能要求一般——slice
slice增加切片范围
这时候,我们对slice重新获取一个范围的数据
地址空间是没有变化的,说明这个slice还是原来的slice,只是修改了内部的状态end的结束位置的状态,不需要重新分配的
make
make([]int, len, cap)
因为我们并不能真正去分配1个切片出来,底层都是有数组来切片,我们在make的时候可以通过预留一定的cap的方式,就算原来的len不够了,也不会去重新分配一个新的数组,而是可以往后继续扩容,扩容到超过大小了,再去重新分配空间
我们现在给slice添加东西
append是专门给slice添加东西的
slice的地址本身不会变,我们怎么办呢:
append自动去做了扩容的操作。
又满了,我们再添加1个呢?
append自动帮我们扩容,以二倍扩容的方式
底层是重新分配一个数组空间出来,然后装这些新的东西