在 Go 语言中,make
和 new
是两个用于分配内存的关键字,但它们的用途和使用场景有明显区别:
1. new
关键字
用途
-
new
用于为类型分配一块零值化的内存,并返回指向这块内存的指针。 -
返回值始终是一个指针,指向所分配类型的内存地址(例如:
*int
、*struct
)。
适用场景
-
当你需要获得某个类型的指针,但不需要初始化内部数据结构时,使用
new
。 -
常用于分配基本数据类型(如
int
、float64
)或自定义的结构体。
示例代码
package main import "fmt" func main() { // 使用 new 分配内存 p := new(int) // 分配一个 int 类型的内存,值为 0,返回指针 fmt.Println(*p) // 输出 0 *p = 42 // 修改指针指向的值 fmt.Println(*p) // 输出 42 }
特点:
-
分配的内存是零值初始化的(对于
int
是 0,对于string
是""
,对于struct
的字段是其各自的零值)。 -
只分配内存,但不会进一步初始化数据结构。
2. make
关键字
用途
-
make
仅用于创建和初始化内置的数据结构(slice
、map
和channel
)。 -
返回的是已经初始化的非零值(如初始化后的
slice
或map
),而不是指针。
适用场景
-
当你需要创建和使用
slice
、map
或channel
时,使用make
。 -
它不仅分配了内存,还完成了必要的初始化,使得这些数据结构可以直接使用。
示例代码
package main import "fmt" func main() { // 使用 make 创建一个 slice s := make([]int, 5, 10) // 创建一个长度为 5,容量为 10 的 slice fmt.Println(s) // 输出 [0 0 0 0 0] // 使用 make 创建一个 map m := make(map[string]int) m["key"] = 42 fmt.Println(m) // 输出 map[key:42] // 使用 make 创建一个 channel c := make(chan int, 2) c <- 1 c <- 2 fmt.Println(<-c) // 输出 1 }
特点:
-
必须配合
slice
、map
和channel
使用。 -
这些数据结构的零值(
nil
)是不可用的,因此必须通过make
初始化。
3. new
与 make
的区别
特性 | new | make |
---|---|---|
适用类型 | 任意类型 | 仅适用于 slice 、map 、channel |
返回值 | 指针(*T ) | 初始化后的具体类型(T ) |
是否初始化 | 只分配内存,零值初始化 | 分配内存并完成初始化 |
使用场景 | 基本类型或自定义类型的指针分配 | 创建可用的 slice 、map 或 channel |
4. 何时使用 new
和 make
使用 new
的场景:
-
当你需要分配基本类型(如
int
、float64
)或结构体的内存,并获得一个指针。 -
例如,需要在堆上分配内存,并通过指针修改其值:
p := new(int) // 分配 int 的内存 *p = 100 // 使用指针修改值
使用 make
的场景:
-
当你需要初始化和使用
slice
map
或
channel
时:
-
slice
:需要预分配容量以提高性能或控制大小。 -
map
:需要确保map
可用(未初始化的map
是nil
,无法使用)。 -
channel
:需要设置缓冲区大小,或创建无缓冲通道。
-
5. 常见误区
-
试图使用
new
创建slice
或map
会导致运行时错误:
m := new(map[string]int) // m 是 *map 类型,未初始化 (*m)["key"] = 42 // 运行时错误:分配的 map 没有初始化
正确方式:
m := make(map[string]int) // 初始化 m["key"] = 42 // 正常使用
总结
-
new
: 用于分配任意类型的零值内存,返回指针;适合结构体或基本类型。 -
make
: 用于分配并初始化内置数据结构(slice
、map
、channel
),返回初始化后的对象,直接可用。