15|同构复合类型:从定长数组到变长切片
该思维导图由 AI 生成,仅供参考
数组有哪些基本特性?
- 深入了解
- 翻译
- 解释
- 总结
Go语言中的切片类型是一种灵活的复合数据类型,它弥补了数组固定长度和传值开销较大的不足。切片与数组类似,但具有动态长度和动态扩容的特性,使其成为Go语言中最常用的同构复合类型之一。切片在运行时实际上是一个三元组结构,包含指向底层数组的指针、切片长度和切片容量。通过内置函数append和切片切片化语法,可以动态地向切片中添加元素或基于已存在的数组创建切片。切片的灵活性使其成为数组的“描述符”,在函数参数传递时避免较大性能开销。此外,多个切片可以共享同一底层数组,对底层数组的操作会反映到其他切片中。切片的动态扩容机制使其成为Go语言中重要的数据类型,为开发者提供了更为便利和高效的数据处理方式。 文章还介绍了切片的动态扩容过程,以及动态扩容可能导致的“绑定关系”解除问题。此外,文章还对数组和切片的特点进行了对比,强调了切片作为数组“描述符”的轻量性和动态扩容的优势。最后,文章提出了一个思考题,期待读者对两个切片变量的差异进行描述。 总之,本文通过深入浅出的方式介绍了Go语言中切片类型的特点和优势,对于想要快速了解切片在Go语言中的应用和特性的读者来说,是一篇值得阅读的文章。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(43)
- 最新
- 精选
- Darren课后题测试代码如下: var sl1 []int var sl2 = []int{} fmt.Print("========基本区别=========\n") fmt.Printf("%v,len:%d,cap:%d,addr:%p\n", sl1, len(sl1), cap(sl1), &sl1) fmt.Printf("%v,len:%d,cap:%d,addr:%p\n", sl2, len(sl2), cap(sl2), &sl2) fmt.Printf("sl1==nil:%v\n", sl1 == nil) fmt.Printf("sl2==nil:%v\n", sl2 == nil) a1 := *(*[3]int)(unsafe.Pointer(&sl1)) a2 := *(*[3]int)(unsafe.Pointer(&sl2)) fmt.Print("========底层区别=========\n") fmt.Println(a1) fmt.Println(a2) type SliceDemo struct { Values []int } var s1 = SliceDemo{} var s2 = SliceDemo{[]int{}} bs1, _ := json.Marshal(s1) bs2, _ := json.Marshal(s2) fmt.Print("========序列化区别=========\n") fmt.Println(a1) fmt.Println(string(bs1)) fmt.Println(string(bs2)) ========基本区别========= [],len:0,cap:0,addr:0xc0000a6018 [],len:0,cap:0,addr:0xc0000a6030 sl1==nil:true sl2==nil:false ========底层区别========= [0 0 0] [18601168 0 0] ========序列化区别========= [0 0 0] {"Values":null} {"Values":[]} 可以看到,日常的使用基本是没有区别的,只不过与nil的比较,以及底层数据结构和序列化还是有一定的区别的。 同时go官方推荐使用 var sl1 []int The former declares a nil slice value, while the latter is non-nil but zero-length. They are functionally equivalent—their len and cap are both zero—but the nil slice is the preferred style. 在goland开发时,第二种声明方式会出现黄色下划线,提示需要改动。
作者回复: 思考题完成的很细致,很全面。手动点赞!
2021-11-15786 - 在下宝龙、var sl1 []int var sl2 = []int{} s1是声明,还没初始化,是nil值,底层没有分配内存空间。 s2初始化了,不是nil值,底层分配了内存空间,有地址。 我是这么理解的。
作者回复: 正确✅
2021-11-1549 - trietreesl1未初始化,值为nil,和nil比较返回true sl2初始化为empty slice,和nil比较返回false
作者回复: 正确✅
2021-11-1515 - 风铃个人感觉,在初始化切片的时候,最好的分配项目的需求,分配一定的容量(cap),要不在切片里面的数据多了,每次进行扩容,会消耗大量的内存性能
作者回复: 👍。
2022-02-2339 - 松有个疑问,切片的底层数组,在切片发生自动扩容后,在物理空间上还是连续的吗?
作者回复: 扩容是新分配一段连续的大点的内存,原先的内存块不要了。所以依旧是连续的。
2022-01-2858 - 笑忘日月星辰老师好,关于扩容,麻烦解惑下 问题:扩容当小于1024时候,是扩容为当前的2倍;当大于1024小于1280时候扩容为1.25倍,当大于1280小于1696时候,扩容为1.325倍吗?这个扩容的规则是什么? func main() { var s []int for i := 0; i < 2048; i++ { s = append(s, i) fmt.Println(len(s), cap(s)) } } 打印结果 --------------------------------------------------- 512 512 513 1024 ... 1024 1024 1025 1280 ... 1280 1280 1281 1696 ... 1696 1696 1697 2304 ...
作者回复: 你用的是什么版本的go编译器,go 1.18,如果是go 1.18,那么可以看https://mp.weixin.qq.com/s/4wYrwBwnuylSvTaxBMXUgg ,go 1.18对slice的扩容算法了调整。
2022-06-255 - 左卫康思考题:var sl1 []int 仅声未初始化,值为对应类型的零值,nil var sl2 = []int{} 声明并初始化,是个空切片
作者回复: ✅
2022-08-05归属地:北京3 - 和白白var sl1 []int 不显示初始化,所以 sl1 对应 slice 的零值 nil,并且此时没有 ptr、len 和 cap var sl2 = []int{} 显示初始化,sl2 对应 [] 空数组,ptr 指定空数组的地址,len 和 cap 都是 0
作者回复: ✅
2022-03-073 - 布凡老师,请问下为什么go没有class 这个类型呢?是因为想要开发者多用组合少用继承的设计理念吗?还是有其它原因呢?
作者回复: class是面向对象语言的专有名词。go定位就不是oo语言,所以没有class。
2021-11-1533 - Aeinssl1 自身有分配内存(能取地址),底层数组没有分配内存。为什么值会是 nil 呢?
作者回复: 首先是否为nil与自身是否能取地址无关。 var p *int = nil println(&p) // 这取地址也是可以的。 切片是复合数据类型,如果其没有被初始化,那么go语言规定其默认的零值就为nil。
2022-05-262