go中创建指针仅有三种合法方式:①&取地址(最常用,支持字面量加括号);②new(t)仅分配零值内存;③reflect.new用于运行时动态构造。结构体指针支持自动解引用,基础类型需手动解引用。

Go 里创建指针对象没有“步骤教程”这种东西——只有三种明确、互不重叠的合法方式,选错会导致字段未初始化、编译报错或运行时 panic。
用 & 取地址是最常用也最安全的方式
这是日常开发中 95% 场景该用的方法,尤其适合结构体。它能直接初始化字段,语义清晰,且 Go 编译器从 1.15 起已支持对复合字面量加括号后取地址。
- ✅ 正确:先声明再取址 ——
u := User{Name: "Alice", Age: 30}; ptr := &u - ✅ 正确:直接取带括号的字面量地址 ——
ptr := &User{Name: "Bob", Age: 25} - ❌ 错误:漏括号或字段顺序依赖 ——
&User{"Charlie", 35}(易出错,不推荐) - ⚠️ 注意:
&User{}是零值,等价于new(User),但可读性更好;而&42或&"hello"是非法的,基本类型字面量不可取地址
new(T) 只做零值分配,别指望它初始化字段
new 是一个内置函数,不是构造器。它只负责分配内存并清零,返回 *T,但所有字段都是默认值(int 是 0,string 是 "",*int 是 nil),不支持传参、不调用任何逻辑。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- ✅ 合法:获取零值指针 ——
p := new(int),u := new(User) - ✅ 等价但更推荐写法:
u := &User{}(语义更直白) - ❌ 无效尝试:
new(User{Name: "X"})会编译失败 ——new不接受参数 - ⚠️ 隐藏风险:若后续忘记赋值就解引用
*u.Name类字段,可能引发空指针 panic(比如u.Name是nil *string)
reflect.New 用于运行时动态构造,不是常规初始化手段
当你需要根据字符串类型名(如配置项 "user")在运行时生成结构体指针时,才轮到 reflect.New。它和 new 或 & 完全不在同一使用层级。
- ✅ 正确用法:先拿到
reflect.Type(必须是值类型,不是指针!),再调reflect.New(t)——t := reflect.TypeOf(User{}); v := reflect.New(t) - ❌ 常见错误:
reflect.TypeOf(&User{})得到的是*User类型,reflect.New会返回**User,解包时容易 panic - ⚠️ 性能代价:反射有明显开销,别在热路径用;且返回的是
reflect.Value,需调.Interface()才能得到真实指针,类型断言不能少 - ? 典型场景:插件系统、配置驱动组件、通用 JSON 解析器中批量构造结构体切片
最容易被忽略的点是:结构体指针字段访问时的自动解引用机制 —— ptr.Name = "x" 是合法的,(*ptr).Name = "x" 等价但冗余,而 *ptr.Name 是语法错误。这个特性只对结构体生效,对 *int 这类基础类型指针仍需手动 *p = 42。混淆这两者,是新手 panic 的高频原因。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










