
博客主页:🏆看看是李XX还是李歘歘 🏆
🌺每天分享一些包括但不限于计算机基础、算法等相关的知识点🌺
💗点关注不迷路,总有一些📖知识点📖是你想要的💗
相同之处 属于集合类的类型,值都可以用来存储某一种类型的元素;在内存布局中都是连续分配的。 区别 数组的长度固定;slice的值长度可变。数组长度在声明的时候就必须给定,并且之后不会再改变。slice类型的字面量中只有元素类型,没有长度(可以在使用make函数时候初始化时添加长度和容量),切片长度可以自动随着元素数量的增长而增长,但不会随着元素数量的减少而减少。⛽️今天的内容是 Go的Slice和数组 ⛽️💻💻💻
数组是值类型(值类型有基本数据类型,结构体类型);切片属于引用类型(引用类型:字典类型,通道类型,函数类型),引用类型不需要使用额外的内存并且比使用数组更有效率。
如果传递的参数是引用类型,那么就是“传引用”,如果传递的是值类型,那么就是“传值”(会把以前的数据复制一遍)
数组的长度=容量,不可改变;切片长度<=容量,动态扩容;
Slice源码slice的容量和长度都是可以进行动态扩容的。
type slice struct {
array unsafe.Pointer
len int
cap int
}
array:指向slice中第一个元素地址
len:slice长度
cap:slice容量
长度必须小于等于容量,通过len()和cap()函数分别返回slice的长度和容量。
关于长度和容量的定义,在源码中关于len()和cap()的定义如下:
|
|
slice或者map:参数v中元素的个数,如果v是nil,则长度为0
|
|
slice:当重新切片时,切片能够搜索到的最大长度。
在切片(slice)中,长度代表它包含的元素的个数(遍历时候,以len()为基准),容量代表从它的第一个元素开始计数,到其底层数组元素末尾的个数,所以说,len是永远小于等于cap的。
|
|
len(b)长度即4-3=1;cap(b)容量即10-3=7。
Slice的扩容 首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),扩容后切片的容量(newcap)就是新申请的容量(cap);否则判断,如果旧切片的长度小于1024,则扩容后切片的容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap);否则判断,如果旧切片长度大于等于1024,则扩容后切片的容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap+=newcap/4),直到扩容后切片的容量(newcap)大于等于新申请的容量(cap),即(newcap>=cap);如果扩容后切片的容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。 slice之append时原数组发生变化的问题 append函数append用于往slice中添加元素或者合并两个slice,函数append()总是会增加slice的长度,而容量可能回改变,也可能不会改变,这取决于被 *** 纵切片的可用容量。
如果nums的cap够用,则会直接在nums指向的数组后面追加元素,返回的slice和原来的slice是同一个对象。显然,这种情况下原来的slice的值会发生变化!如果nums的cap不够用,则会创建一个新的底层数组空间用来存储数据,将被引用的现有的值复制到新数组里,再添加元素,返回指向新数组的slice。这时候原来的slice指向的数组并没有发生任何变化!补充:为了更好的使用append()函数实现追加元素,为底层数组提供一定的保护,建议使用切片的第三个索引来限制新切片的容量。
切片是引用类型,可能多个切片使用同一个底层数组,对切片的内容进行修改可能影响多个切片,如果能限制容量和长度相等,则追加元素时一定会新建一个切片。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)