惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Stack Overflow Blog
Stack Overflow Blog
Forbes - Security
Forbes - Security
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
N
News | PayPal Newsroom
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
Vercel News
Vercel News
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
Google Online Security Blog
Google Online Security Blog
Simon Willison's Weblog
Simon Willison's Weblog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
T
Tenable Blog
I
InfoQ
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
D
DataBreaches.Net
博客园 - Franky
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
S
Security @ Cisco Blogs
Hacker News: Ask HN
Hacker News: Ask HN
J
Java Code Geeks
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Full Disclosure
C
Cisco Blogs
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Cloudflare Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
The GitHub Blog
The GitHub Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
F
Fortinet All Blogs
Jina AI
Jina AI
V
Visual Studio Blog
L
LINUX DO - 热门话题
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏

博客园 - 川川籽

minikube dashboard ImagePullBackOff 失败问题的解决方法 hashicorp/raft模块实现的raft集群存在节点跨集群身份冲突问题 macos 13安装openvpn - 川川籽 [转发] Go pprof内存指标含义备忘录 自己搭建一个https的dns,让不同的浏览器使用不同的DNS,使用相同的域名访问到不同的主机上 记一次docker buildx build 推送到本地私有仓库出现 connection refused 的问题 Linux C 获取本机IPV4和IPV6地址列表 Mac M1 安装python3.6.x golang map 和 interface 的一些记录 MacOS M1 安装python3.5 使用php的openssl_encrypt和python的pycrypt进行跨语言的对称加密和解密问题 golang random string 【转载】coroutine 与 goroutine 区别 python简单的time ticker 'invalid flag in #cgo LDFLAGS: -w' 问题解决 记录一次python的mysqlclient依赖库报错问题 airflow当触发具有多层subDAG的任务的时候,出现[Duplicate entry ‘xxxx’ for key dag_id]的错误的问题处理 Python3并发写文件 python hash 每次调用结果不一样
GO面试题:new 和 map 的区别
川川籽 · 2026-04-03 · via 博客园 - 川川籽

在 Go 语言中,newmake 都是用于内存分配的内建函数,但它们的适用类型、行为方式和返回值有本质区别。

核心区别

特性 new make
适用类型 任意类型(包括结构体、整数、数组等) 仅限 slicemapchannel 三种内置引用类型
返回值 指向该类型的指针*T 返回该类型本身(T,不是指针),且已初始化
内存行为 分配内存并置零值,不初始化内部结构 分配内存并初始化内部结构(如 slice 的底层数组、map 的哈希桶、channel 的缓冲区等)
使用场景 获取一个可指向零值对象的指针 创建可立即使用的 slice、map、channel

详细说明

1. new 函数

  • 签名:func new(Type) *Type
  • 作用:分配足够存储 Type 值的内存,将其所有位初始化为零值(zero value),并返回该内存地址的指针。
  • 结果:指针指向一个零值对象,适合需要指针但暂时不需要填充具体数据的场景。
p := new(int)      // p 是 *int,指向 0
fmt.Println(*p)    // 输出 0
*p = 42
type Person struct {
    Name string
    Age  int
}
p := new(Person)   // p 是 *Person,Name="", Age=0

2. make 函数

  • 签名:make(Type, size ...) Type(具体参数依类型而定)
  • 作用:只用于 slicemapchannel,不仅分配内存,还会初始化它们的内部数据结构(如 slice 的 lencap 和底层数组,map 的哈希桶等),返回已初始化的该类型值(非指针)。
  • 结果:直接可用的引用类型值。
// slice: 类型, len, cap
s := make([]int, 3, 5)   // len=3, cap=5,底层数组有5个元素,前3个为0

// map: 类型, 可指定容量(hint)
m := make(map[string]int) // 等价于 map[string]int{}

// channel: 类型, 可指定缓冲区大小
ch := make(chan int, 10)  // 缓冲区容量为10

为什么需要两个函数?

  • new 只负责分配内存并返回指针,不关心类型的内部结构。对于 slice、map、channel 这种需要复杂初始化的类型,仅仅置零(例如 nil slice、nil map、nil channel)是不够的,必须调用 make 完成内部数据结构的初始化才能正常使用。
  • 例如:var m map[string]intnew(map[string]int) 得到的 nil map 无法直接写入数据(会 panic),而 make(map[string]int) 得到的空 map 可以安全写入。
var m1 map[string]int   // nil map
m1["a"] = 1             // panic: assignment to entry in nil map

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

使用new初始化map等内置引用类型后,该如何进行读写操作

使用 new(map[string]int) 得到的是一个指向 nil map 的指针(*map[string]int 类型)。这个指针本身不是 nil,但它指向的 map 是 nil,因此无法直接读写(会 panic)。要让它变得可用,必须让该指针指向一个已初始化的 map。

如下示例:

package main

import "fmt"

func main() {
	fmt.Println("Hello, 世界")

	v := new(int)
	fmt.Println(v, *v)

	m1 := new(map[string]int)
	fmt.Println("m1:", m1, "| *m1:", *m1)
	fmt.Println("m1 == nil:", m1 == nil)   // false(指针本身不是 nil)
	fmt.Println("*m1 == nil:", *m1 == nil) // true(指向的 map 是 nil)

	// `m1`是一个指向nil的map的指针,这个指针本身不是 nil,但它指向的 map 是 nil,因此无法直接读写(会 panic)。要让它变得可用,必须让该指针指向一个已初始化的 map。
	// 当你写 *m1["key"] 时,编译器会先执行 m1["key"],但 m1 的类型是 *map[string]int(指向 map 的指针),而指针类型不支持索引操作,所以会编译报错:invalid operation: cannot index m1 (variable of type *map[string]int)
	// m1["a"] = 1 // 写操作会引发错误:invalid operation: cannot index m1 (variable of type *map[string]int)
	// fmt.Println(m1["a"]) // 读操作也会引发错误,原因同上。

	// 为了让编译器先解引用指针得到 map,再对 map 进行索引,必须用括号改变运算顺序:`(*m1)["key"]`
	// 类似的情况也出现在通过指针访问结构体字段时:(*p).field,但 Go 提供了语法糖 p.field,会自动解引用。可惜 map 索引没有这种语法糖,所以必须显式写括号。

	// (*m1)["a"] = 1 // panic: assignment to entry in nil map
	fmt.Println("未初始化m1 | (*m1)[\"a\"] = ", (*m1)["a"]) // 可以读

	// 必须初始化
	*m1 = make(map[string]int) // 现在 *m1 是一个空 map
	(*m1)["a"] = 1             // 可以进行读写操作
	fmt.Println("已初始化m1 | (*m1)[\"a\"] =", (*m1)["a"])
}

输出:

Hello, 世界
0x14000098030 0
m1: &map[] | *m1: map[]
m1 == nil: false
*m1 == nil: true
未初始化m1 | (*m1)["a"] =  0
已初始化m1 | (*m1)["a"] = 1