利志分享
fast_forward
view_headline
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
go基础知识
go的环境搭建
go变量
go常量
go字符串
go数组和切片
go的map和range的使用
go的struct的使用
go的函数使用
go的interface的使用
go channel使用
go的routine使用
go的panic和recover使用
go实现http请求
go 复杂的http请求
go实现表单提交
go实现表单验证
go上传附件
go实现mysql连接
go实现redis操作
go对xml操作
go的json操作
go的base64使用
go实现websocket功能
go的单元测试
go的文件操作
go的web服务基础
golang url解析和包介绍使用
go的正则表达式-MatchString,FindString等的使用
golang实现从byte和文件中读取csv格式数据
go进阶
go的类型转换
go的map的多维应用
go的多维数组和slice使用
go的select使用
go的原子性atomic类库使用
go给图片添加水印
go给图片添加文字
go实现http的rpc服务
go实现tcp的rpc服务
go实现json格式的rpc服务
多个defer的执行问题
golang的队列机制实现同步主线程接受子协程的结果
go的值传递和引用传递以及引用类型的问题
go中的make和new的使用问题
golang读文件分析1
golang读文件分析2
golang实现自然周计算
golang实现读写excel
go实战
beego的安装和使用
beego聊天室的基本配置
beego聊天室的生成
Go 写一个类似 cron 的定时任务管理器
Go 调度器 M, P 和 G
AES对称加密算法如何用golang语言实现?
非对称加密的RSA算法如何通过golang来实现?
golang实现http2.0服务端,客户端完整案例
go实战总结
go的日期操作类使用-日常使用类库no.1
go的字符串的连接讲解-日常实战总结no.1
golang实现队列服务-日常实战总结no.2
深入理解golang的channel的使用-日常实战总结no.3
go的sync.pool在实际应用中的讲解和性能分析比较-日常实战总结no.4
go语言中一个典型的引用类型的数据使用案例的注意点-日常实战总结no.5
go的sync包的使用详解1-日常实战总结6
go的sync包的使用详解2-日常实战总结7
深度学习go判断各个类型相等-日常实战总结8
go的排序类使用讲解-日常实战总结9
go的context使用讲解
golang 网络爬虫框架gocolly
golang实现桶排序
golang处理gb2312转utf-8编码的问题
golang实现单链的添加,删除以及翻转
golang的一个err不判断引起的血案(json.Marshal的error到底要不要判断?)
如何控制golang协程的并发数量问题-panic: too many concurrent operations on a single file or socket (max 1048575)
你所要知道的redis客户端返回值知识点
golang实现连续的时间,比如连续的天,月,年等。
go深入
由引用类型引发的概念的深入理解
sync.WaitGroup深入源码理解
golang如何创建动态的struct类型以及如何转换成slice类型
深入理解go的管道数据读写
关于go的只读管道只写管道以及单向管道的理解
深入理解go的slice深入,slice扩容机制
深入理解go的函数参数传递
golang实现动态调用不同struct中不同的方法
如何配置sqlx.DB的SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime来保证更好的性能
深入理解go的select原理
深入理解golang的GPM模型
精通golang的项目管理go modules
深入理解golang的GC回收机制
超级肝文-深入剖析客户端出现connect reset by peer报错相关的技术知识
Golang源码深入-Go1.15.6发起http请求流程-1
Golang源码深入-Go1.15.6发起http请求流程-2
Golang源码深入-Go1.15.6发起http请求流程-3(http2)
go应用
需求整理-手把手带大家用go开发一个匿名在线聊天室
第二篇-手把手带大家用go开发一个匿名在线聊天室
第三篇-手把手带大家用go开发一个匿名在线聊天室
go面试
【建议收藏】吐血整理Golang面试干货21问-吊打面试官-1
【建议收藏】整理Golang面试第二篇干货13问
【建议收藏】Redis知识干货汇总
【建议收藏】Mysql知识干货(mysql八股文)汇总
目录
go基础知识
go的环境搭建
go变量
go常量
go字符串
go数组和切片
go的map和range的使用
go的struct的使用
go的函数使用
go的interface的使用
go channel使用
go的routine使用
go的panic和recover使用
go实现http请求
go 复杂的http请求
go实现表单提交
go实现表单验证
go上传附件
go实现mysql连接
go实现redis操作
go对xml操作
go的json操作
go的base64使用
go实现websocket功能
go的单元测试
go的文件操作
go的web服务基础
golang url解析和包介绍使用
go的正则表达式-MatchString,FindString等的使用
golang实现从byte和文件中读取csv格式数据
go进阶
go的类型转换
go的map的多维应用
go的多维数组和slice使用
go的select使用
go的原子性atomic类库使用
go给图片添加水印
go给图片添加文字
go实现http的rpc服务
go实现tcp的rpc服务
go实现json格式的rpc服务
多个defer的执行问题
golang的队列机制实现同步主线程接受子协程的结果
go的值传递和引用传递以及引用类型的问题
go中的make和new的使用问题
golang读文件分析1
golang读文件分析2
golang实现自然周计算
golang实现读写excel
go实战
beego的安装和使用
beego聊天室的基本配置
beego聊天室的生成
Go 写一个类似 cron 的定时任务管理器
Go 调度器 M, P 和 G
AES对称加密算法如何用golang语言实现?
非对称加密的RSA算法如何通过golang来实现?
golang实现http2.0服务端,客户端完整案例
go实战总结
go的日期操作类使用-日常使用类库no.1
go的字符串的连接讲解-日常实战总结no.1
golang实现队列服务-日常实战总结no.2
深入理解golang的channel的使用-日常实战总结no.3
go的sync.pool在实际应用中的讲解和性能分析比较-日常实战总结no.4
go语言中一个典型的引用类型的数据使用案例的注意点-日常实战总结no.5
go的sync包的使用详解1-日常实战总结6
go的sync包的使用详解2-日常实战总结7
深度学习go判断各个类型相等-日常实战总结8
go的排序类使用讲解-日常实战总结9
go的context使用讲解
golang 网络爬虫框架gocolly
golang实现桶排序
golang处理gb2312转utf-8编码的问题
golang实现单链的添加,删除以及翻转
golang的一个err不判断引起的血案(json.Marshal的error到底要不要判断?)
如何控制golang协程的并发数量问题-panic: too many concurrent operations on a single file or socket (max 1048575)
你所要知道的redis客户端返回值知识点
golang实现连续的时间,比如连续的天,月,年等。
go深入
由引用类型引发的概念的深入理解
sync.WaitGroup深入源码理解
golang如何创建动态的struct类型以及如何转换成slice类型
深入理解go的管道数据读写
关于go的只读管道只写管道以及单向管道的理解
深入理解go的slice深入,slice扩容机制
深入理解go的函数参数传递
golang实现动态调用不同struct中不同的方法
如何配置sqlx.DB的SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime来保证更好的性能
深入理解go的select原理
深入理解golang的GPM模型
精通golang的项目管理go modules
深入理解golang的GC回收机制
超级肝文-深入剖析客户端出现connect reset by peer报错相关的技术知识
Golang源码深入-Go1.15.6发起http请求流程-1
Golang源码深入-Go1.15.6发起http请求流程-2
Golang源码深入-Go1.15.6发起http请求流程-3(http2)
go应用
需求整理-手把手带大家用go开发一个匿名在线聊天室
第二篇-手把手带大家用go开发一个匿名在线聊天室
第三篇-手把手带大家用go开发一个匿名在线聊天室
go面试
【建议收藏】吐血整理Golang面试干货21问-吊打面试官-1
【建议收藏】整理Golang面试第二篇干货13问
【建议收藏】Redis知识干货汇总
【建议收藏】Mysql知识干货(mysql八股文)汇总
深入理解go的slice深入,slice扩容机制
阅读:827
分享次数:0
关于slice是go里面最常见也用得最多的数据结构,我们翻一下源码看下结构,路径在Go/src/runtime/slice.go文件里面。 type slice struct { array unsafe.Pointer len int cap int } slice是由一个array指针指向底层数组,len表示切片长度,cap表示切片容量。其实关于slice的理解,主要是要知道它的扩容机制,了解扩容机制就能深刻理解slice。 首先我们来看一个例子: package main import "fmt" func main() { slice1 := []int{} oldCap := cap(slice1) for i := 0; i < 2048; i++ { slice1 = append(slice1, i) newCap := cap(slice1) if newCap != oldCap { fmt.Printf("%p %p cap=%d\n", &slice1, slice1, cap(slice1)) oldCap = newCap } } } 执行结果如下: 0xc000004480 0xc00000a0b0 cap=1 0xc000004480 0xc00000a0e0 cap=2 0xc000004480 0xc0000103c0 cap=4 0xc000004480 0xc00000e200 cap=8 0xc000004480 0xc000018100 cap=16 0xc000004480 0xc000000500 cap=32 0xc000004480 0xc000076000 cap=64 0xc000004480 0xc000078000 cap=128 0xc000004480 0xc00007a000 cap=256 0xc000004480 0xc00007c000 cap=512 0xc000004480 0xc00007e000 cap=1024 0xc000004480 0xc000110000 cap=1280 0xc000004480 0xc00011a000 cap=1696 0xc000004480 0xc000124000 cap=2304 上面slice1,它的地址是不变的,但是他执行的值是变化的,初始化的时候是0xc00000a0b0,第一次增加内容会扩容所以值得地址是变化的,因为复制了内存,slice1的指向新的一块内存。第二次,第三次,slice1的容量都是够的,到第三次刚好是初始化的两倍,第四次的时候扩容之后slice1又指向了新的地址。上面的例子能够很好的说明slice的扩容变化。我们这里下面总结一下: 扩容的基本原则: 1. 如果slice的容量小于1024,则新的扩容会是原来的2倍。 2. 如果原来的slice的容量大于或者等于1024,则新的扩容将扩大大于或者等于原来1.25倍(网上其实很多总结都是错误的。)。 对于切片的扩容,当切片比较小的,采用较大的扩容倍速进行扩容,避免频繁扩容,从而减少内存分配的次数和数据拷贝的代价。 当切片较大的时,采用较小的扩容倍速,主要避免空间浪费。 对于append向slice添加元素的步骤: 1. 加入slice容量够用,则追加新元素进去,slice.len++,返回原来的slice。 2. 当原容量不够,则slice先扩容,扩容之后得到新的slice,将元素追加进新的slice,slice.len++,返回新的slice。 下面我们再看一个特殊的例子: package main import "fmt" func main() { s := []int{5} s = append(s, 7) s = append(s, 9) x := append(s, 11) y := append(s, 12) fmt.Printf("s:%v, x:%v, y:%v", s, x, y) } 结果如下: s:[5 7 9], x:[5 7 9 12], y:[5 7 9 12] 为什么x和y的值是一样呢?如果看完上面的扩容机制,相信大家都能知道,当执行x := append(s, 11)这行代码的时候容量是4,所以11是直接加到s里面去的,当执行y := append(s, 12)这行代码的时候容量还是4,所以12是直接追加到s里面去的,把之前那个11进行覆盖了,因为给x赋值和给y赋值,s在执行s = append(s, 9)这行代码的时候已经扩容好了还剩下一个位置,所以给x和y的赋值都是追加到s的最后一个位置。所以会出现x和y是最后相同的值。 最后我们看看这个例子: package main import "fmt" func main() { s := []int{5, 7, 9} x := append(s, 11) y := append(s, 12) fmt.Printf("s:%v, x:%v, y:%v", s, x, y) } 结果如下: s:[5 7 9], x:[5 7 9 11], y:[5 7 9 12] 这里的x和y就会不一样。原因是因为s执行x := append(s, 11)的时候扩容了,执行了y := append(s, 12)也在s的基础上进行扩容了,扩容了之后x和y指向的是不同的内存,x和y有不同的内存地址。 slice扩容总结: - **如果slice的容量小于1024,则新的扩容会是原来的2倍。** - **如果原来的slice的容量大于或者等于1024,则新的扩容将扩大大于或者等于原来1.25倍。**
感觉本站内容不错,读后有收获?
attach_money
我要小额打赏,鼓励作者写出更好的教程
扫码关注公众号:talk_lizhi