基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

make 和 new 的区别是什么?

知识点图片

在 Go 语言中,makenew 都是用于内存分配的内建函数,但它们的作用对象、返回类型以及底层行为有非常明显的区别。

简单总结:

  • new:只分配内存,不初始化内存(只置为零值),返回指针
  • make:分配内存并初始化内部数据结构,返回(仅用于 slice, map, channel)。

详细对比

1. new 函数

  • 语法func new(Type) *Type
  • 作用
    1. 为类型 Type 分配一块内存。
    2. 将这块内存的内容清零(即设置为该类型的零值,如 int 为 0,bool 为 false)。
    3. 返回指向这块内存的指针*Type)。
  • 适用类型:任意类型(包括基本类型、结构体等)。
  • 类比:就像给你一个空盒子,里面什么都没有(或者说是默认的填充物),但把盒子的地址给了你。

示例

go
p := new(int)   // p 的类型是 *int
fmt.Println(*p) // 输出 0 (int 的零值)

type Student struct {
    Name string
    Age  int
}
s := new(Student) // s 的类型是 *Student
fmt.Println(s.Name) // 输出 "" (string 的零值)

2. make 函数

  • 语法func make(t Type, size ...IntegerType) Type
  • 作用
    1. 分配内存。
    2. 初始化底层的数据结构(不仅仅是清零,还包括设置长度、容量、哈希桶、等待队列等)。
    3. 返回该类型的Type),而不是指针。
  • 适用类型:仅限 slice(切片)map(字典)channel(通道)
  • 原因:这三种类型在 Go 内部是复杂的结构,必须经过初始化才能使用。例如,slice 内部包含指向底层数组的指针、长度和容量;如果只用 new 分配内存而不初始化这些字段,slice 就无法正常工作。
  • 类比:就像给你一台手机,不仅硬件(内存)准备好了,操作系统也启动了(初始化),你可以直接拿来用。

示例

go
// 创建一个包含 10 个整数的切片
s := make([]int, 10) // s 的类型是 []int
s[0] = 100           // 可以直接使用

// 创建一个 map
m := make(map[string]int) // m 的类型是 map[string]int
m["key"] = 1              // 可以直接赋值

// 创建一个 channel
c := make(chan int) // c 的类型是 chan int

核心区别总结表

特性 new(T) make(T, args)
作用对象 任意类型 (int, struct, array 等) 仅限 slice, map, channel
返回类型 指针 *T T (这三种类型本身就是引用语义)
内存状态 分配内存并置为零值 分配内存并初始化内部结构
主要用途 获取指向零值的指针 创建可用的引用类型对象

为什么 make 不返回指针?

这是一个常见的问题。因为 slice、map 和 channel 在 Go 中属于引用类型

  • Slice:本质上是一个结构体,包含 {ptr, len, cap}
  • MapChannel:本质上是指向底层复杂结构的指针。

当你使用 make 时,你想要的是那个可以直接操作的“句柄”(handle)。如果 make 返回指针,你得到的就是“指向 slice 结构体的指针”,在使用时会非常麻烦(需要解引用)。

错误用法示例

如果你尝试用 new 来创建 map,会发生 panic,因为 map 没有被初始化:

go
// 错误示范
var m *map[string]int
m = new(map[string]int) // 分配了 map 的指针,但 map 内部结构未初始化
// (*m)["key"] = 1      // 运行时错误:panic: assignment to entry in nil map

// 正确示范
m2 := make(map[string]int)
m2["key"] = 1 // 正常工作

总结

  • 如果你需要一个 slice、map 或 channel,请使用 make
  • 如果你需要结构体或基本类型的指针,请使用 new(或者更常用的字面量语法 &Type{})。
00:00
00:00