
在 Go 语言中,new(T) 和 &T{} 对于任意类型 T(尤其是结构体)完全等价,均返回指向零值的指针,语义与行为无任何差异。
在 go 语言中,`new(t)` 和 `&t{}` 对于任意类型 `t`(尤其是结构体)完全等价,均返回指向零值的指针,语义与行为无任何差异。
在 Go 的内存分配与初始化实践中,常会遇到两种看似不同的指针创建方式:new(T) 和 &T{}。初学者容易误以为二者存在语义、性能或适用范围上的区别,但事实是——它们在所有场景下完全等价。
根据官方文档《Effective Go》明确指出:
“As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. The expressions new(File) and &File{} are equivalent.”
这意味着,无论 T 是结构体、数组、切片(零长度)、映射还是其他可寻址类型,只要 T 是合法的类型,new(T) 与 &T{} 就严格等价:
- 二者均分配一块足以容纳 T 的零初始化内存;
- 二者均返回 *T 类型的指针;
- 二者均不调用任何构造函数(Go 无构造函数概念),也不触发 init() 或自定义逻辑;
- 编译器对二者生成的机器码通常一致,无运行时开销差异。
✅ 正确示例(结构体):
type Person struct {
Name string
Age int
}
p1 := new(Person) // p1 == &Person{}
p2 := &Person{} // p2 == new(Person)
fmt.Printf("%+v, %+v\n", *p1, *p2) // {Name:"", Age:0} {Name:"", Age:0}✅ 同样适用于基础复合类型:
s := new([]int) // s == &[0]int{}? ❌ 错!注意:[]int 是切片(引用类型)
// 正确对比应为:
a := new([3]int) // → *[3]int,值为 [3]int{0,0,0}
b := &[3]int{} // 等价于 a
m := new(map[string]int // ❌ 编译错误:map 不可取地址,new(map[string]int 合法,但 &map[string]{} 非法
// 因此需注意:&T{} 要求 T 可寻址且支持复合字面量(即必须是结构体、数组、切片字面量等),而 new(T) 对类型约束更宽松(支持任意类型,包括 map、chan、func)。⚠️ 关键注意事项:
- &T{} 仅对支持复合字面量的类型有效,即:结构体(struct)、数组([N]T)、切片字面量([]T{})、映射字面量(map[K]V{})等。它不能用于 map、chan、func 等类型,因为这些类型没有对应的空复合字面量语法。
- new(T) 则适用于任意类型 T(包括 map[string]int、chan int、func() 等),始终返回该类型的零值指针(例如 *map[string]int 是一个指向 nil map 的指针)。
因此,虽然 new(T) ≡ &T{} 在结构体和数组等场景下成立,但二者类型适用范围并不完全重合——这是唯一实质性的“区别”,且属于语法限制层面,而非语义或行为差异。
? 总结建议:
- 对于结构体/数组初始化,优先使用 &T{}:更直观、符合 Go 复合字面量惯用法,且便于后续添加字段(如 &Person{Name: "Alice"});
- 若需为 map、chan 等类型获取零值指针(极少见),只能使用 new(T);
- 在代码审查或教学中,应明确传达:二者在共同适用范围内功能、性能、安全性完全一致,选择应基于可读性与上下文一致性,而非误解的“优劣”。










