导读:本期聚焦于小伙伴创作的《Go语言中new()和make()区别是什么?哪些类型必须用make()?》,敬请观看详情。为什么同样的零值初始化,用new去处理slice却拿不到可用底层数组?这背后是Go对引用类型的特殊处理。new只负责分配内存并返回指针,不触发结构内部的初始化逻辑;make专门面向slice、map、channel这三种内置引用类型,会一并设置长度、容量或运行时结构。如果强行用new创建map,得到的是nil指针,直接赋值会panic。只有make能为它们建立真正的可用状态。弄清二者差异,能避免很多运行时错误。

在Go语言里,new()make()都用于内存分配,但设计目标完全不同。理解它们的差异,是写出稳定Go程序的基础,尤其在处理slice、map和channel时,选错函数会直接导致运行时崩溃。

Go语言中new()和make()区别是什么?哪些类型必须用make()?

new()的工作机制

new()是Go内置的一个函数,接收一个类型参数,为该类型分配零值内存,并返回指向这块内存的指针。它不关心类型内部结构,只是单纯地把内存清零。比如new(int)返回一个*int,指向值为0的int;new(struct)返回结构体指针,字段全是对应零值。

从实现角度看,new(T)等价于&T{}的取地址行为,但语法上更明确表达分配意图。由于它返回的是指针,调用者需要通过*p解引用访问。下面的代码展示了new的基本用法:

package main

import "fmt"

func main() {
    p := new(int)
    fmt.Println(*p) // 输出0
    *p = 10
    fmt.Println(*p) // 输出10

    type User struct {
        Name string
        Age  int
    }
    u := new(User)
    fmt.Println(u.Name, u.Age) // 输出空字符串 0
}

可以看到,new对任何类型一视同仁,都只是分配并清零。它不会为slice建立底层数组,也不会为map创建哈希表头,这正是和make的关键分水岭。

make()的专门用途

make()只用于三种内置引用类型:slice、map、channel。它不但分配内存,还会初始化类型内部的数据结构,让返回值处于可用状态。以slice为例,make会分配底层数组,并设置长度与容量;map会建立哈希表运行时结构;channel会创建缓冲队列或同步变量。

make的返回值不是指针,而是类型本身(如[]intmap[string]intchan int)。这与new截然不同。下面分别展示三种类型的make用法:

package main

import "fmt"

func main() {
    // slice
    s := make([]int, 3, 5)
    s[0] = 1
    fmt.Println(s, len(s), cap(s))

    // map
    m := make(map[string]int)
    m["a"] = 1
    fmt.Println(m)

    // channel
    c := make(chan int, 2)
    c <- 10
    fmt.Println(<-c)
}

如果这里把map换成new(map[string]int),得到的是*map[string]int,且指向nil,直接(*m)["a"]=1会panic。只有make能产出非nil且可写的map。

哪些类型必须用make

必须用make的类型只有三个:slice、map、channel。它们是Go运行时特殊管理的引用类型,零值nil不代表可用。new可以给它们分配指针,但无法初始化内部描述符,因此不具备读写能力。

具体规则如下:

  • slice:必须用make或字面量(如[]int{1,2})创建,new得到的*[]int指向nil slice,无法直接下标赋值。
  • map:必须用make或字面量(如map[string]int{})创建,new得到nil map指针,写入会panic。
  • channel:必须用make创建并指定缓冲大小或0,new得到nil chan指针,收发操作永久阻塞或panic。

其他所有类型,包括基础类型、数组、结构体、指针等,都可以用new或直接字面量。数组长度固定,new([3]int)返回可用指针;结构体用new也能正常字段赋值。因此,make的强制范围严格限定在上述三类。

常见误区与对比总结

很多初学者认为new和make只是语法糖差异,其实不然。下面的表格列出核心区别:

对比项new(T)make(T, args)
适用类型任意类型仅slice、map、channel
返回值*T(指针)T(类型本身)
内存状态零值,无内部初始化已初始化,可用
nil安全性返回非nil指针,但可能指向nil引用返回非nil可用对象

一个典型错误是试图用new创建map后直接赋值:

package main

func main() {
    m := new(map[string]int)
    // 下面这行会panic,因为*m是nil map
    (*m)["x"] = 1
}

正确做法是用make(map[string]int)。在代码评审中,看到引用类型创建应优先确认是否用了make。掌握这条边界,能显著减少Go程序中的nil pointer和nil map赋值panic。

newmakeGo类型初始化修改时间:2026-08-03 17:06:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。