今天我们来聊聊一个大家面试中经常遇到的问题:Golang 中的 new 和 make 到底有什么区别?这两货看起来名字差不多,但用法和场景可大不一样。为了方便大家理解,我来掰扯掰扯。

先说 new
这个函数名字虽然简单,但功能还挺关键。new 是 Go 语言的内置函数,它的作用就是分配内存,然后返回指向该内存地址的指针。

通俗点讲,new 干的事情就是帮你“造个房子”,不过它不负责装修,也就是只提供一个空的空间。这就意味着你通过 new 创建的对象,只是分配了内存,没有初始化内容,默认值是零值。

举个例子吧,new(int) 会返回一个指向 0 的指针,而 new([]int) 则会返回一个指向空 slice 的指针。

那 make 呢?

它也是 Go 的内置函数,但它比 new 功能更多,不仅帮你分配内存,还顺手把房子装修好,给你提供一个能直接使用的 slice、map 或 channel。

这里要注意了,make 只能用于 slice、map 和 channel 这三种引用类型。就像一个包工头,make 不但帮你建了房子,还把家具摆好,水电全都接通了,直接拎包入住。比如,make([]int, 10) 会创建一个长度为 10 的 slice,并且可以直接使用。

看到了吧?new 和 make 的区别就在这:new 是给你一个空的房间指针,你得自己来填充内容;而 make 是给你一个已经装修好的房间,可以直接用。new 主要用于结构体或数组这种值类型的指针分配,而 make 则是专门服务于 slice、map 和 channel。

既然我们在讲 Go 语言的内置函数,那顺便提一下格式化输出吧,很多人对 Printf、Sprintf 和 Fprintf 这三兄弟也分不清。其实,它们的区别主要在于输出的“目的地”不同。

先说 Printf

这个函数最常用,它的输出目标是标准输出,也就是你的屏幕。比如你在调试的时候,fmt.Printf(“Hello, %s”, “world”) 就会在屏幕上输出“Hello, world”。

再说 Sprintf

这个函数和 Printf 的格式化功能一样,但它不是直接往屏幕上输出,而是返回一个格式化好的字符串,适合你把结果存在变量里再做其他处理。比如 s := fmt.Sprintf(“Hello, %s”, “world”),会把“Hello, world”存在字符串变量 s 中。

最后是 Fprintf

它则是把格式化后的字符串输出到指定的地方,通常是文件或者其他 IO 设备,比如你想把日志写到文件里,可以用 fmt.Fprintf(file, “Log entry: %d”, 1)。

说完这些基础函数,咱们再来说点面试中的“坑”

我之前面试时碰到一个很经典的考点:面试官让你用 new 创建一个 slice,你怎么回答?

一般来说,这种问题是挖了坑等你跳的,因为 new([]int) 虽然返回了 slice 的指针,但这个 slice 并不能用,它只是一个空壳子,啥都没有。真正想用 slice,你还是得用 make,比如 make([]int, 0) 这样才能得到一个可以添加元素的 slice。

再举个例子,创建 map 的时候也是同样道理。new(map[string]int) 只能得到一个空 map 的指针,而 make(map[string]int) 则是直接返回一个可以用的 map。

因此,在开发中,尽量用 make 来初始化 slice、map 或 channel,因为它们都是引用类型,需要内存分配和初始化才能正常工作。

从这个例子也可以看出,new 和 make 的使用场景真的差别很大。new 更像是为你准备了个空模板,得靠你自己去填充;而 make 是直接给你一个完整的实例,拎包入住。所以面试时千万别把这俩搞混了,特别是在需要实际操作 slice、map 和 channel 的时候,一定要用 make 来搞定。

总结

new 更适合用于分配指针类型,而 make 是专门为 Go 语言中的三种引用类型服务的。如果你面试的时候遇到这些问题,记得先问问自己:“我只是要个空指针,还是想要一个可以用的实例?”这句话就能让你对 new 和 make 的使用瞬间清晰。

个人笔记记录 2021 ~ 2025