浅谈Golang Slice切片如何扩容的实现
作者:头秃猫轻王 发布时间:2024-04-29 13:06:28
一、Slice数据结构是什么?
切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片(slice)是可以看做是一个长度可变的数组。
切片(slice)自身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。
切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。
二、详细代码
1.数据结构
slice的结构体由3部分构成,Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。cap 总是大于等于 len 的。
通常我们在对 slice 进行 append 等操作时,可能会造成slice的自动扩容。
代码如下(示例):
type slice struct {
array unsafe.Pointer
len int
cap int
}
2.扩容原则
如果切片的容量小于1024个元素,那么扩容的时候slice的cap就乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。
如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。
3.如何理解扩容规则一
规则一:
如果切片的容量小于1024个元素,那么扩容的时候slice的cap就乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。
1.当小于1024个元素时
代码如下(示例):
func main() {
// 建立容量为 2 的 切片
addCap := make([]string, 0, 2)
// 插入一个数,占一个容量
addCap = append(addCap, "1")
// 打印此时的地址
fmt.Println("addCap 1", addCap, cap(addCap), &addCap[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap = append(addCap, "1")
fmt.Println("addCap 2", addCap, cap(addCap), &addCap[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap = append(addCap, "1")
// 此时三个数已经超出容量,那么切片容量将扩容,此时地址也将变成新的地址
fmt.Println("addCap 3", addCap, cap(addCap), &addCap[0])
}
结果(示例):
2.当大于1024个元素时
代码如下(示例):
func main() {
// 建立容量为 1022 的 切片
addCap1024 := make([]int, 1022, 1024)
// 插入一个数,占一个容量 容量 1023
addCap1024 = append(addCap1024, 1)
// 打印此时的地址
fmt.Println("addCap1024 1", cap(addCap1024), &addCap1024[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap1024 = append(addCap1024, 1)
fmt.Println("addCap1024 2", cap(addCap1024), &addCap1024[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap1024 = append(addCap1024, 1)
// 此时三个数已经超出容量1024,那么切片容量将扩容,此时地址也将变成新的地址
fmt.Println("addCap1024 3", cap(addCap1024), &addCap1024[0])
}
结果(示例):
此时容量Cap 增加了 1280 - 1024 = 256 ,也就是 1024 的 25 %
即 增长因子就变成1.25,即每次增加原来容量的四分之一。
4.如何理解扩容规则二
规则一:
如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。
1.简单理解内存地址更换
代码如下(示例):
func main() {
// 建立容量为 2 的 切片
addCap := make([]string, 0, 2)
// 插入一个数,占一个容量
addCap = append(addCap, "1")
// 打印此时的地址
fmt.Println("addCap 1", addCap, cap(addCap), &addCap[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap = append(addCap, "1")
fmt.Println("addCap 2", addCap, cap(addCap), &addCap[0])
// 将 oth 的指针指向切片地址
// 再打印此时的地址 和 addCap 一样,即未触及容量时,还是原数组
oth := addCap[0:1]
fmt.Println("oth 1",oth,cap(oth),&oth[0])
//此时修改原数组 oth 所指向的地址不变,但第一个数的值已经更改 3
addCap[0] = "3"
fmt.Println("oth 2",oth,cap(oth),&oth[0])
// 插入一个数,占一个容量
// 再打印此时的地址
addCap = append(addCap, "1")
//此时再修改 已经是扩容后的新地址 原数组将保持不变 即oth 所指向的地址的值不变
addCap[0] = "4"
// 此时三个数已经超出容量,那么切片容量将扩容,此时地址也将变成新的地址,第一个数也将修改为 4
fmt.Println("addCap 3", addCap, cap(addCap), &addCap[0])
// 但 oth 依然保留着原数组的指针地址,所以依然还是 3
fmt.Println("oth 3",oth,cap(oth),&oth[0])
}
结果(示例):
此时容量Oth 指向原切片位置,而扩容后的新的切片指向了新的位置,做的修改将无法影响原切片。
来源:https://blog.csdn.net/moer0/article/details/122933748


猜你喜欢
- 本文实例讲述了Python统计文件中去重后uuid个数的方法。分享给大家供大家参考。具体如下:利用正则表达式按行获取日志文件中的的uuid,
- SCN(System Change Number)作为oracle中的一个重要机制,在数据恢复、Data Guard、Streams复制、R
- 找到nginx多网站配置文件:类似 nginx/sites-available/www.baidu.comserver { li
- 一个网站程序,在添加新闻时出现错误以下是错误提示: Microsoft OLE DB Provide
- beego中各类数据库连接方式beego 框架是优秀得go REST API开发框架。下面针对beego中各类数据库连接操作做一个总结。or
- import socketdef open_tcp_socket(remotehost,servicename): &
- 具体如下: 1>如我们知道开始时间,要加减一个时间,得出一个结果时间,可以用以下代码 $time1='2008-10-1 12
- 前期准备在虚拟开发环境中安装:pip install django-filter在Django的项目配置文件中安装并配置django_fil
- Python的绘图库也允许用户创建优雅的图形,本章给大家介绍的是关于ggplot绘制画图的技巧,ggplot2建立在grid系统上,这个系统
- 总结了部分所学、所听、所看、所问的一些CSS写作经验,书写高效的CSS - 漫谈CSS的渲染效率,它们与渲染效率及所占用
- 图像噪声是指存在于图像数据中的不必要的或多余的干扰信息。在噪声的概念中,通常采用信噪比(Signal-Noise Rate, S
- Python中的模块(.py文件)在创建之初会自动加载一些内建变量,__name__就是其中之一。Python模块中通常会定义很多变量和函数
- 一、Requests库的安装利用 pip 安装,如果你安装了pip包(一款Python包管理工具,不知道可以百度哟),或者集成环境,比如Py
- 目录安装pytest插件编写测试用例忽略 HTTPS 错误和设置自定义视口大小持久上下文playwright结合Pytest为您的 Web
- MySQL 触发器MySQL 数据库中触发器是一个特殊的存储过程,不同的是执行存储过程要使用 CALL 语句来调用,而触发器的执行不需要使用
- 本文为大家讲解了pytorch实现CNN卷积神经网络,供大家参考,具体内容如下我对卷积神经网络的一些认识卷积神经网络是时下最为流行的一种深度
- 发现很多朋友对 CSS 的优先权不甚了解,规则很简单。需要说明的一点,如果你的样式管理需要深层判断 CSS 的优先权,更应反思自己的 CSS
- 这问题在网络相信已经有不少人问到,最近再次被牵起讨论,籍此记录一下个人的理解,border:none;与border:0;的区别体现有两点:
- 1 Support Vector Machines1.1 Example Dataset 1%matplotlib inlineimport
- 大家好,我是小五前一阵给大家分享了,Python如何给图片加水印。评论区就有小伙伴问,可不可使用Python去除图片水印的方法呢?这个肯定有