TonyBai · Go 语言进阶课
Tony Bai
资深架构师
586 人已学习
新⼈⾸单¥59
TonyBai · Go 语言进阶课
15
15
1.0x
00:00/00:00
登录|注册

04 | 数组与切片:性能、灵活与陷阱,如何做出最佳选择?

你好,我是 Tony Bai。
上一讲我们深入学习了值与指针以及 Go 的值传递机制。今天,我们要聚焦 Go 语言中使用频率最高的两种复合类型:数组(array)和切片(slice)。相信你对它们已经不陌生了。
数组是由相同类型元素组成的复合类型,Go 会为每个数组类型实例分配一块连续的内存。一旦创建,数组的元素个数和大小就固定不变。
而切片可以理解为动态数组,它的元素类型也是相同的,但其底层数组(underlying array)的大小会随着调用 append 函数添加元素而自动扩展。所有这些操作都由 Go 运行时自动完成,程序员无需显式干预。
在日常 Go 开发中,切片以其无与伦比的灵活性,在很多场景下取代了数组,成为处理同构(相同类型)元素集合的首选。
但切片的这种灵活性并非没有“代价”。你是否思考过:
数组的“死板”背后,隐藏着哪些性能优势?
切片的“灵活”背后,又有哪些潜在的性能开销和不易察觉的“陷阱”?
比如,nil 切片和空切片有何不同?append 导致底层数组“分家”是怎么回事?for range 遍历切片时有什么坑?
在追求性能和追求灵活性之间,我们应该如何明智地选择使用数组还是切片?
这节课,我们就来深入剖析数组和切片的核心差异、性能权衡以及常见的陷阱。掌握这些,你才能真正驾驭好数组和切片这两个 Go 语言的利器。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
  • 解释
  • 总结

1. 数组和切片是 Go 语言中使用频率最高的两种复合类型,数组的元素个数和大小固定不变,而切片的底层数组大小会随着添加元素而自动扩展。 2. 切片以其无与伦比的灵活性,在很多场景下取代了数组,成为处理同构元素集合的首选。 3. 数组适用于大小固定且对性能有极致要求的场景,或作为其他数据结构的底层存储,而切片胜在灵活、方便、传参代价低。 4. 空切片和 nil 切片的区别在于底层内存表示,空切片的 data 值不为零,但并没有在堆上额外分配新的内存空间作为切片的底层数组。 5. 切片的自动扩容特性在底层内存管理上给我们带来理解复杂性,需要深入理解切片的机制和潜在问题。 6. 在追求性能和追求灵活性之间,需要明智地选择使用数组还是切片。 7. 只有通过 Go 预定义的 append 函数向切片追加元素的过程中,才会触发切片实例的自动扩容。 8. 切片扩容后的新老切片彻底分家,影响的仅仅是分家后的新切片及其底层数组,原切片中的元素并未受到影响。 9. 数组转切片是零拷贝的,而切片转数组指针 (1.17+) 是零拷贝;切片转数组 (1.20+)是拷贝。 10. 默认使用切片:对于大多数需要处理序列数据的场景,切片的灵活性和易用性使其成为首选。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《TonyBai · Go 语言进阶课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(2)

  • 最新
  • 精选
  • 徐石头
    func ModifyBytes(b []byte) { b[0] = 'a' fmt.Println("Inside ModifyBytes: b =", b) } func ModifyBytesPanic(b []byte) { b[4] = 'a' fmt.Println("Inside ModifyBytes: b =", b) } func ModifyBytesReturn(b []byte) []byte { b[0] = 'a' return b } func ModifyBytesPoint(b *[]byte) { (*b)[0] = 'a' return } func TestModifyBytes(t *testing.T) { b1 := []byte("123") // ModifyBytesPanic(b1) // panic: runtime error: index out of range [4] with length 3 fmt.Println("Before ModifyBytes: b1 =", b1) ModifyBytes(b1) fmt.Println("After ModifyBytes: b1 =", b1) b2 := []byte("123") b2result := ModifyBytesReturn(b2) fmt.Println("After ModifyBytesReturn: b2result =", b2result) b3 := []byte("123") ModifyBytesPoint(&b3) fmt.Println("After ModifyBytesPoint: b3 =", b3) } 个人选择func Transform(data []byte) []byte(传入切片,返回一个新的切片),对函数调用方而言,切片是经过修改的,这是明确的,如果不返回新切片,函数内部修改值后,而调用方不知道,可能有意外的 bug,而且,函数内如果扩容,也不影响调用方
    2025-05-19归属地:湖南
  • 程序员阿煜
    如果只是可能会改变元素值,但不会改变切片的长度,说明在函数内部不会由于切片扩容而导致创建新切片,那么使用func Transform(data []byte)即可。
    2025-05-19归属地:四川
收起评论
显示
设置
留言
2
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部