Go语言里的make和new有什么区别

问答Go语言里的make和new有什么区别
王利头 管理员 asked 1 年 ago
3 个回答
Mark Owen 管理员 answered 1 年 ago

在 Go 语言中,make 和 new 都是内置函数,用于创建新的数据结构。虽然它们的功能相似,但底层机制却截然不同,这一点至关重要。

make

  • 用途:用于创建切片、映射和通道等复合数据结构。
  • 语法:make(type, size) 或 make(type, size, capacity)
  • 返回值:返回一个已初始化的复合数据结构,其中元素的值为零值。
  • 底层机制:make 直接在底层内存中分配空间,并初始化为零值。它不分配单独的底层数组,而是直接操作内存。

示例:

go
mySlice := make([]int, 5) // 创建一个长度为 5 的整数切片
myMap := make(map[string]int) // 创建一个空映射
myChannel := make(chan int, 10) // 创建一个容量为 10 的通道

new

  • 用途:用于创建指针类型的值,该指针指向底层数据结构。
  • 语法:new(type)
  • 返回值:返回一个指向新分配内存的指针,该内存已初始化为零值。
  • 底层机制:new 在堆上分配内存,并创建一个指向该内存的指针。它分配一个单独的底层数组,供指针指向。

示例:

go
myPtr := new(int) // 创建一个指向整数的指针
*myPtr = 10 // 通过指针反引用并赋值

make 和 new 的关键区别

| 特征 | make | new |
|—|—|—|
| 返回值类型 | 复合数据结构 | 指针 |
| 底层内存分配 | 直接分配在内存中 | 在堆上分配 |
| 初始化 | 初始化为零值 | 初始化为零值 |
| 适用数据结构 | 切片、映射、通道 | 指针类型 |

哪一个更适合我?

make 和 new 根据不同的使用场景而有特定的优势:

  • 使用 make 创建复合数据结构,当您希望直接操作内存并避免指针开销时。
  • 使用 new 创建指针类型的变量,当您需要手动管理底层内存分配和引用时。

总的来说,make 对于创建简单的复合数据结构更方便,而 new 则适用于需要更多控制和灵活性的情况。

深入案例分析

以下是一些更高级的示例,展示了 make 和 new 在不同情况下的应用:

示例 1:

创建一个切片,其中的元素是另一个切片的引用:

go
mySlice := make([][]int, 3) // 创建一个引用 3 个空切片的切片

示例 2:

创建一个映射,其中的键是字符串,值是整数的指针:

go
myMap := make(map[string]*int) // 创建一个映射,其中键为字符串,值为整数指针

示例 3:

分配一个结构体的内存,并返回一个指向该结构体的指针:

go
myStruct := new(MyStruct) // 创建一个 MyStruct 类型的指针
myStruct.field1 = "value1" // 通过指针反引用并赋值

通过了解 make 和 new 之间的细微差别,您可以选择最适合您特定需求的功能,从而编写高效且可维护的 Go 代码。

seoer788 管理员 answered 1 年 ago

Go语言中,makenew都是用来分配内存的内置函数,但它们在使用方式和语义上存在着一些关键区别。

分配类型

new用于分配一个新变量,该变量的类型是一个指针类型。分配的内存大小是该类型的零值大小。

go
x := new(int) // 分配一个指向int零值的指针

make用于分配一个新变量,该变量的类型是一个切片、映射或通道。分配的内存大小根据所提供的类型而定。

go
slice := make([]int, 10) // 分配一个长度为10的int切片

初始化

new分配的变量必须使用*解引用才能访问其值。这个值是分配的指针类型对应的零值。

go
fmt.Println(*x) // 输出0

make分配的变量不需要解引用,因为它们本身就是值类型。分配的值已经使用类型的零值进行了初始化。

go
fmt.Println(slice[0]) // 输出0

容量

对于切片和映射,make还可以指定容量。容量定义了分配的底层数组或哈希表的最大大小。如果超出容量,Go会自动分配一个更大容量的新底层数组或哈希表。

go
slice := make([]int, 10, 20) // 分配一个长度为10、容量为20的int切片

对于通道,make指定通道的缓冲容量。缓冲容量定义了在通道阻塞之前可以存储在通道中的值的数量。

go
ch := make(chan int, 10) // 分配一个缓冲容量为10的int通道

性能

在某些情况下,makenew具有更好的性能。这是因为make可以直接为特定类型分配内存,而new需要分配一个额外的指针对象。这个性能差异对于频繁分配大量对象的情况下尤为明显。

何时使用make和new

  • 使用make:当需要分配一个切片、映射或通道时,应使用make。它还可以指定这些类型的容量。
  • 使用new:当需要分配一个指针类型变量时,应使用new。分配的变量必须使用*解引用才能访问其值。

使用注意事项

  • new分配的指针变量必须始终在使用前进行初始化。
  • make分配的切片、映射或通道的容量可能会随着值的添加而动态增长。
  • 在分配大对象时,应考虑内存分配的性能影响。
ismydata 管理员 answered 1 年 ago

在Go语言中,makenew都是用于创建对象和值的重要关键字。虽然这两个关键字都用于内存分配,但它们在用法和语义上却大不相同。

make:切片、映射、通道

make主要用于创建切片、映射和通道。切片是一个动态大小数组,映射是一种键值对集合,而通道是通信和同步机制。

使用make创建切片,需要指定切片的长度和容量。容量是切片可以容纳的最大元素数量。默认情况下,容量为长度的两倍。

go
mySlice := make([]int, 5, 10) // 创建一个长度为5,容量为10的int切片

使用make创建映射,需要指定映射的键类型和值类型。

go
myMap := make(map[string]int) // 创建一个string键、int值映射

使用make创建通道,需要指定通道的数据类型。

go
myChannel := make(chan int) // 创建一个int类型通道

new:指针

new用于创建指向新对象的指针。该对象将分配在堆内存中,并返回指向该对象的指针。

go
myObject := new(MyObject) // 创建一个MyObject对象并返回指向它的指针

new返回的指针是空指针,它不指向任何有效的对象。因此,使用new创建对象后,通常需要显式对其进行初始化,以避免使用未初始化的指针。

go
myObject = &MyObject{} // 显式初始化myObject

make vs. new

归纳起来,makenew的区别如下:

  • 用途: make用于创建切片、映射和通道,而new用于创建指针。
  • 分配: make分配并初始化对象,而new仅分配并返回指向对象的指针。
  • 返回值: make直接返回对象,而new返回指向对象的指针。
  • 内存管理: make分配的切片、映射和通道是在栈内存中管理的,而new分配的对象是在堆内存中管理的。

何时使用make

  • 需要创建动态大小的切片、映射或通道时。
  • 需要指定切片或映射的初始大小和容量时。

何时使用new

  • 需要创建自定义结构或类的对象时。
  • 需要显式管理对象生命周期时。
  • 需要返回指向对象的指针(例如,在接口实现中)时。

例子

为了展示makenew的不同用法,我们来看一个简单的示例。假设我们有一个Person结构体,表示一个人的姓名和年龄。

使用make创建切片:

go
people := make([]Person, 2) // 创建一个长度为2的Person切片
people[0] = Person{"Alice", 25} // 初始化第一个元素
people[1] = Person{"Bob", 30} // 初始化第二个元素

使用new创建指针:

go
person := new(Person) // 创建一个指向Person对象的指针
person.name = "Charlie" // 初始化姓名
person.age = 40 // 初始化年龄

在这个示例中,make直接创建了一个包含两个Person元素的切片,而new创建了一个指向Person对象的指针,该对象需要显式初始化。

公众号