最稳妥的结构体指针初始化方式是 &T{},语义清晰、支持字段名赋值、自动逃逸上堆且符合标准库风格;new(T) 已属历史遗留,日常开发基本无需使用;var u *T 声明后为 nil,需判空防 panic。

声明结构体指针变量的三种常见写法
Go 里没有“结构体指针类型”的独立语法,*T 就是结构体指针类型,其中 T 是结构体名。关键不是“怎么声明”,而是“何时用哪种方式初始化”——因为声明后若未赋值,就是 nil,直接解引用会 panic。
假设结构体定义为:
type User struct {
Name string
Age int
}
以下是实际开发中最常遇到的三种场景:
-
声明并立即取地址:用
&User{},得到非 nil 指针,字段按零值初始化u := &User{Name: "Alice", Age: 30}(推荐用于构造实例) -
先声明指针变量,再分配内存:用
new(User),返回指向零值User的指针var u *User = new(User)(等价于&User{},但不支持字段初始化) -
仅声明,不初始化:用
var u *User,此时u == nil,必须检查后再解引用if u != nil { fmt.Println(u.Name) }(常见于函数参数或可选配置)
为什么不能直接写 var u *User{}?
这是初学者典型误区:*User{} 不是合法的复合字面量语法。Go 规定:只有类型字面量(如 User{})或其取地址形式(&User{})才允许带字段初始化;*User 是类型,不是结构体字面量类型。
立即学习“go语言免费学习笔记(深入)”;
下面写法全部报错:
var u *User{} // syntax error: unexpected {, expecting semicolon or newline
var u *User = {} // cannot use {} (type struct {}) as type *User
u := *User{} // cannot use *User{} (type *User) as type *User in assignment
正确做法始终围绕 User{} 或 &User{} 展开。
在函数参数和返回值中怎么用?
接收或返回结构体指针,是为了避免拷贝、支持修改原值,但要注意 nil 安全性。
- 函数参数声明为
*User,调用时传&u(如果u是User类型)或直接传u(如果u已是*User) - 函数返回
*User,内部应确保返回非 nil(除非明确约定可返回 nil),例如:func NewUser(name string) *User { return &User{Name: name} } - 若函数可能无法构造有效实例,建议返回
(*User, error),而不是裸指针 —— 避免调用方忽略 nil 判断
容易被忽略的 nil 解引用陷阱
结构体指针变量默认是 nil,但 Go 不会在声明时自动分配内存。很多 bug 来自忘记检查就直接访问字段:
var u *User fmt.Println(u.Name) // panic: invalid memory address or nil pointer dereference
这类错误在以下情况高发:
- struct 字段本身是
*T类型,且未显式初始化(如type Order struct { User *User }) - 从 map 或 slice 中取值后未判断是否存在(
m["key"]对 map 返回零值,对*T就是nil) - JSON 反序列化时字段为指针,但原始 JSON 缺失该字段 → 得到
nil而非零值结构体
真正需要警惕的,从来不是“怎么声明”,而是“什么时候它其实是 nil”。


















