[GoLang避坑实战-08] 切片扩容的惨剧:为什么共享底层数组让你哭都哭不出来?

大家好,我是极客老墨。 写 Go 之前,我在 Java 里用 ArrayList、HashMap 这些集合类。转到 Go 发现只有数组、切片、map 三种,心想"这够用吗?" 结果发现 Go 的切片是动态数组,自动扩容,比 Java 的 ArrayList 还简洁。map 就是哈希表,但遍历顺序是随机的,这点要注意。 这篇就聊聊 Go 数组、切片和 map 的几个关键特性和几大隐蔽却常见的坑。 数组:长度固定,很少用 Go 的数组长度是类型的一部分,[3]int 和 [4]int 是不同类型: 1var arr [3]int = [3]int{10, 20, 30} 2fmt.Println(arr) // [10 20 30] 3 4// 让编译器推导长度 5arr2 := [...]int{1, 2, 3, 4, 5} ⚠️ 注意:数组是值类型,赋值和传参会复制整个数组。 数组的几种初始化方式 1// 指定索引初始化 2arr := [5]int{0: 10, 2: 20, 4: 30} // [10, 0, 20, 0, 30] 3 4// 部分初始化(其余为零值) 5arr2 := [5]int{1, 2} // [1, 2, 0, 0, 0] 6 7// 多维数组 8matrix := [2][3]int{ 9 {1, 2, 3}, 10 {4, 5, 6}, 11} 💡 技巧:实际开发中很少直接用数组,都用切片,因为比起固定长度,我们多数更需要的是动态扩容。 ...

2024-08-22 · 5 min · 1061 words · 老墨

(译)Go创造者Rob Pike带你深入了解数组、切片和字符串 底层的 “append” 原理

大家好,我是极客老墨! 今天这篇文章是早期老墨翻译自 Golang 官方博客文章,有一定的深度,非常经典,读完你会深入了解数组、切片和字符串的 Append 原理,建议收藏后细细品味。 原文地址: https://go.dev/blog/slices,Rob Pike 介绍 过程编程语言最常见的特征之一是数组的概念。数组看起来很简单,但在将它们添加到语言时必须回答许多问题,例如: 固定尺寸还是可变尺寸? 大小是类型的一部分吗? 多维数组是什么样的? 空数组有意义吗? 这些问题的答案会影响数组是否只是语言的一个特性还是其设计的核心部分。 在 Go 的早期开发中,在设计感觉正确之前,花了大约一年的时间来确定这些问题的答案。关键步骤是引入 slices(切片),它建立在固定大小的 array (数组)之上,以提供灵活、可扩展的数据结构。然而,直到今天,刚接触 Go 的程序员经常对切片的工作方式感到困惑,也许是因为其他语言的经验影响了他们的思维。 在这篇文章中,我们将尝试消除混淆。我们将通过构建片段来解释 append 内置函数是如何工作的,以及为什么它会以这种方式工作。 数组 数组是 Go 中的一个重要构建块,但就像建筑物的基础一样,它们通常隐藏在更可见的组件之下。在我们继续讨论更有趣、更强大、更突出的切片概念之前,我们必须简单地讨论一下它们。 数组在 Go 程序中并不常见,因为数组的大小是其类型的一部分,这限制了它的表达能力。 以下代码: 1var buffer [256]byte 声明了一个数组变量 buffer ,[256]byte 表示它持有的数据类型为 byte,长度为 256。如果想声明 512 个字节的数组可以这样: [512]byte。 与数组关联的数据就是 数组中的元素。上边声明的数组缓冲区在内存中看起来像这样: 1buffer: byte byte byte ... 256 times ... byte byte byte 也就是说,该变量只保存 256 个字节的数据,仅此而已。我们可以使用熟悉的索引语法 buffer[0]、buffer[1] 到 buffer[255] 来访问它的元素。(索引范围 0 到 255 涵盖 256 个元素)尝试使用超出此范围的索引值访问 buffer 会使程序崩溃。 内置函数 len 会返回数组、切片或其他一些数据类型中的元素数量。在我们的示例中,len(buffer) 返回固定值 256。 数组有它们适合的使用场景 —— 例如,它们是转换矩阵的良好表示,但它们在 Go 中最常见的用途是为切片保存存储空间。 ...

2023-02-09 · 8 min · 1613 words · 老墨