★ make、new 与零值有什么区别?

一句话结论:new(T) 分配一块零值内存并返回 *T(对任意类型可用);make 只服务于 slice/map/channel 三种引用类型,返回初始化好的非指针值;而“零值”指声明后不赋值时的默认值,slice/map/channel 的零值是 nil——三者最易踩的坑是 nil map 写入会 panic、nil channel 会永久阻塞。

三种机制对比

项目new(T)make(T)零值声明
适用范围任意类型仅 slice/map/channel任意类型
返回值*T(指针)T(已初始化)直接使用变量
内部结构仅置零,无底层结构分配底层数组/哈希表/缓冲nil
典型写法p := new(int)s := make([]int, 0, 8)var s []int

var s []int 得到 nil 切片;make([]int, 0, 8) 得到非 nil 的空切片。两者都能 append,但判 nil、序列化结果不同。

零值可用性速查

  • nil 切片:可 append(会新分配)、可 len/cap、可 range;等于 nil。
  • nil map:可读(返回零值)、可 len、可 range;写入 panic。
  • nil channel:收发都会永久阻塞;close(nil) 会 panic。
  • 结构体零值:字段各自为零值,指针/slice/map 字段为 nil,多数场景可直接使用。
var m map[string]int
m["a"] = 1 // panic: assignment to entry in nil map

m2 := make(map[string]int)
m2["a"] = 1 // 正常

var c chan int
// <-c // 若执行会永久阻塞,只能靠收发配对解开

p := new(int) // *int 类型,*p == 0
*p = 42

s := make([]int, 0, 8) // 空但非 nil
var s2 []int           // nil
fmt.Println(s == nil, s2 == nil) // false true

常见追问 / 记忆点

  • 追问:什么时候用 new?——很少;需要零值指针时 new(T) 与 &T{} 等价,后者更常见。
  • 追问:nil 切片与空切片序列化一样吗?——encoding/json 中 nil 切片编码为 null,空切片为 [],二者不等价。
  • 记忆点:make 只给 slice/map/channel 用;零值背三句——slice 能用、map 能读不能写、channel 会堵。
笔记加载中…