Make vs. New: A Comprehensive Guide for Go Developers
2023-10-28 16:27:22
make vs. new: 揭开 Go 中内存分配的神秘面纱
在编程的浩瀚世界中,为特定任务选择正确的工具至关重要。在 Go 语言中,两个基本的——make 和 new——经常让开发者感到困惑。尽管它们都作为分配函数,但它们有不同的用途和细微差别,可能会对你的代码产生天壤之别。
理解 make:切分和组合数据结构
make 是一个多功能函数,专门用于创建和初始化 Go 内置的数据结构,即切片、映射和通道。它的优势在于能够为这些结构分配内存,并返回一个指向新创建实例的引用,让你可以无缝地使用它们。
make 的神奇之处:创建切片、映射和通道
- 切片: make([]T, length, capacity) 返回一个类型为 T 的切片,具有指定的长度和容量。容量决定了在需要重新分配之前,切片可以容纳的最大元素数。
- 映射: make(map[K]V) 创造一个映射,这是一组键值对的集合,其中 K 表示键类型,V 表示值类型。映射是无序的,这意味着元素不会存储在任何特定序列中。
- 通道: make(chan T, buffer) 实现了一个通道,这是一种通信机制,允许 goroutine 并发地交换数据。缓冲区指定了通道的容量,决定了在发送或接收阻塞之前,它可以容纳多少个值。
深入探究 new:分配原始内存
另一方面,new 采取了不同的方法。它分配一块原始内存,并返回一个指向分配内存的第一个字节的指针。此内存不会自动初始化,由开发者明确赋值。
释放 new 的力量:分配内存块
- 原始内存分配: new(T) 分配一块内存,足以容纳类型为 T 的值。它返回一个指向此未初始化内存的指针。
- 结构分配: new(S) 分配一个类型为 S 的结构的内存,并返回一个指向新创建结构的指针。
明智的选择:make vs. new——何时使用它们
在 make 和 new 之间做出决定需要仔细考虑手头的任务。这里有一些指导原则,可以帮助你做出明智的选择:
- 数据结构优先 make: 当处理切片、映射或通道时,make 是你的不二之选。它简化了初始化、处理内存分配,并提供了一种指定容量或缓冲区大小的便捷方式。
- 原始内存分配选择 new: 如果你需要未初始化的原始内存,new 是你的盟友。它提供对内存分配的细粒度控制,让你可以精确地管理内存使用。
示例:阐明差异
为了巩固你的理解,我们来探索一些实际示例:
make 实践:
// 创建一个容量为 10 的整数切片
slice := make([]int, 5, 10)
// 声明一个从字符串到整数的映射
hash := make(map[string]int)
// 初始化一个容量为 3 的缓冲通道
ch := make(chan int, 3)
new 实践:
// 为一个 float64 值分配内存
ptr := new(float64)
// 创建一个类型为 Person 的新结构
person := new(Person)
结论:精通内存分配的艺术
make 和 new 是 Go 开发者工具库中不可或缺的工具。通过理解它们的不同角色和细微差别,你可以利用它们的强大功能来创建高效且可维护的代码。记住,make 擅长初始化数据结构,而 new 让你可以控制原始内存分配。明智地选择,你将成为 Go 中内存分配艺术的大师。
常见问题解答
1. 什么时候应该使用 new 而不是 make?
new 应该用于分配原始内存块,而 make 专门用于初始化 Go 数据结构。
2. make 返回一个引用,而 new 返回一个指针。有什么区别?
引用和指针都是内存地址,但引用在 Go 中是值类型,而指针是引用类型。这意味着引用的值不能改变,而指针的值(即它指向的内存地址)可以改变。
3. 在分配大型数据结构时,make 和 new 哪个更有效?
make 通常更有效,因为它会自动分配内存并初始化数据结构。另一方面,new 要求你手动管理内存分配和初始化,这可能会更耗时和容易出错。
4. 可以使用 new 来分配切片、映射或通道吗?
是的,你可以使用 new 分配切片、映射或通道的底层数组或对象。但是,这样做通常不推荐,因为 make 提供了更简洁、更有效的方法来初始化这些数据结构。
5. make 和 new 对 goroutine 的并发性有什么影响?
make 和 new 都是 goroutine 安全的,这意味着它们可以在并发环境中安全地使用。