返回

Make vs. New: A Comprehensive Guide for Go Developers

后端

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 安全的,这意味着它们可以在并发环境中安全地使用。