Go中结构体指针最常用且推荐的方式是用&操作符取地址,如&User{Name: "Alice"};new()仅做零值分配且不支持初始化,不推荐用于结构体。

直接用 & 操作符取地址是最常用方式
Go 中没有类似 C 的 malloc 或 Java 的 new 关键字来“分配对象”,结构体指针通常通过取地址操作生成。只要结构体变量已存在,& 就能拿到它的指针。
常见错误是试图对字面量直接取地址却不加括号,比如 &MyStruct{...} 在某些上下文(如函数参数)中会报错:cannot take the address of MyStruct literal —— 实际上 Go 允许这样做,但仅限于可寻址的复合字面量;而临时值(如函数返回的结构体、未命名的字面量)不可取地址。
- ✅ 正确:先声明变量再取地址:
user := User{Name: "Alice", Age: 30} ptr := &user - ✅ 正确:用带括号的复合字面量(Go 1.15+ 支持):
ptr := &User{Name: "Bob", Age: 25} - ❌ 错误(旧版本或部分编译器警告):
ptr := &User{"Charlie", 35}(字段顺序依赖且无括号易出错)
new() 函数只做零值分配,不推荐用于结构体
new(T) 返回 *T,但它只会把内存清零,不会调用任何构造逻辑,也不支持字段初始化。对结构体而言,它返回的是所有字段为零值的指针,比如 int 是 0、string 是 ""、*int 是 nil。
它和 &T{} 行为接近,但更冗长且缺乏可读性。除非你在写泛型工具函数需要统一处理任意类型,否则没必要用 new。
立即学习“go语言免费学习笔记(深入)”;
- ✅ 等价但不推荐:
ptr := new(User) // 所有字段都是零值
- ✅ 更清晰的替代:
ptr := &User{} // 同样是零值,语义明确 - ⚠️ 注意:
new(User)无法指定字段值,也不能触发自定义初始化逻辑
在函数中返回结构体指针时,避免返回局部变量地址
Go 的栈逃逸分析通常能正确处理返回局部结构体指针的情况,但前提是该结构体确实被逃逸到了堆上。如果只是简单地在函数内创建结构体再取地址返回,Go 编译器一般会自动将其分配到堆 —— 这是安全的。
真正危险的是返回指向**栈上数组元素**或**闭包捕获的局部变量地址**这类情况。结构体本身只要不是嵌套在不可寻址上下文中,就无需担心。
- ✅ 安全(编译器自动逃逸):
func NewUser(name string, age int) *User { return &User{Name: name, Age: age} } - ⚠️ 需留意字段含 slice/map/chan 时的深层所有权:它们本身是指针类型,复制结构体指针并不会深拷贝这些字段内容
- ? 小技巧:用
go build -gcflags="-m"可查看变量是否逃逸到堆
使用指针接收者时,初始化方式影响方法调用一致性
如果你的结构体方法定义为指针接收者(如 func (u *User) Save() error),那么调用这些方法的对象必须是指针类型。这时候初始化方式就直接影响能否直接调用。
常见陷阱是用字面量初始化后忘记取地址,导致编译错误:u.Save undefined (type User has no field or method Save) —— 因为方法集只包含 *User,不包含 User。
- ✅ 正确匹配指针接收者:
u := &User{Name: "David"} u.Save() // ✅ OK - ❌ 错误(值类型无法调用指针接收者方法):
u := User{Name: "Eve"} u.Save() // ❌ compile error - ? 提示:若结构体较大或需修改字段,优先设计为指针接收者;初始化时统一用
&T{...}可减少后续调用问题
&MyStruct{Field: value} 初始化,尤其当结构体有指针接收者方法或字段含引用类型时**。别依赖 new,也别省略 & 去碰运气。










