
在 Go 中,普通结构体字面量(如 Point{1, 2})不可寻址,因此不能取地址或作为指针方法的接收者;但 &Point{1, 2} 是语言特设的合法语法糖,它直接构造并返回一个指向新分配结构体的指针,整个表达式本身可求值为地址。
在 go 中,普通结构体字面量(如 `point{1, 2}`)不可寻址,因此不能取地址或作为指针方法的接收者;但 `&point{1, 2}` 是语言特设的合法语法糖,它直接构造并返回一个指向新分配结构体的指针,整个表达式本身可求值为地址。
Go 的可寻址性规则明确:只有变量(即具有内存地址的存储位置)才可取地址。像 Point{1, 2} 这样的纯结构体字面量属于临时值(rvalue),没有固定内存地址,因此 &Point{1, 2} 若被理解为“对字面量取地址”,本应非法——但 Go 专门为此场景定义了语法特例。
根据《The Go Programming Language》第 4.4.1 节,&T{...} 并非对字面量取地址,而是一个原子操作:它等价于先调用 new(T) 分配零值内存,再对解引用后的变量赋值。例如:
pp := &Point{1, 2}
语义上完全等同于:
pp := new(Point) // 分配 *Point,*pp 为零值 Point{}
*pp = Point{1, 2} // 显式赋值
但 &Point{1, 2} 更简洁、更高效(编译器可优化为单次堆/栈分配),且可直接用于表达式上下文,如构造嵌套结构:
type ColoredPoint struct {
*Point
Color color.RGBA
}
// ✅ 合法:&Point{1, 1} 是一个 *Point 类型的值,可直接传入
p := ColoredPoint{&Point{1, 1}, red}
⚠️ 注意事项:
-
&T{...}仅适用于结构体、数组、切片、映射、函数和通道这六种复合类型字面量(见 Go 语言规范 Composite Literals 章节),不适用于基础类型(如&int(42)非法); - 它创建的对象默认分配在堆上(逃逸分析决定),但小对象可能被栈分配;
- 不要误以为
&T{...}是“取地址运算符 + 字面量”的组合——它是独立语法,禁止拆解为&(T{...})(后者会编译失败)。
总结:&Point{1, 2} 的合法性并非例外,而是 Go 为提升开发体验而设计的核心语法特性。它规避了显式 new() + 赋值的冗余,同时严格遵守可寻址性语义——因为最终产生的是一个可寻址的变量的地址,而非对临时值的非法引用。理解这一点,是掌握 Go 值语义与指针语义协同设计的关键。










