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 := &userptr := &User{Name: "
Bob", Age: 25}ptr := &User{"Charlie", 35}(字段顺序依赖且无括号易出错)new() 函数只做零值分配,不推荐用于结构体new(T) 返回 *T,但它只会把内存清零,不会调用任何构造逻辑,也不支持字段初始化。对结构体而言,它返回的是所有字段为零值的指针,比如 int 是 0、string 是 ""、*int 是 nil。
它和 &T{} 行为接近,但更冗长且缺乏可读性。除非你在写泛型工具函数需要统一处理任意类型,否则没必要用 new。
ptr := new(User) // 所有字段都是零值
ptr := &User{} // 同样是零值,语义明确new(User) 无法指定字段值,也不能触发自定义初始化逻辑Go 的栈逃逸分析通常能正确处理返回局部结构体指针的情况,但前提是该结构体确实被逃逸到了堆上。如果只是简单地在函数内创建结构体再取地址返回,Go 编译器一般会自动将其分配到堆 —— 这是安全的。
真正危险的是返回指向**栈上数组元素**或**闭包捕获的局部变量地址**这类情况。结构体本身只要不是嵌套在不可寻址上下文中,就无需担心。
func NewUser(name string, age int) *User {
return &User{Name: name, Age: age}
}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() // ✅ OKu := User{Name: "Eve"}
u.Save() // ❌ compile error&T{...} 可减少后续调用问题&MyStruct{Field: value} 初始化,尤其当结构体有指针接收者方法或字段含引用类型时**。别依赖 new,也别省略 & 去碰运气。