go中用指针只为改原变量或避免大对象拷贝;基本类型和小结构体传值更安全高效;&仅用于可寻址变量;*t接收者用于修改字段,t用于只读;nil指针解引用必panic。

Go 里用指针不是为了“看起来高级”,而是为了解决两个具体问题:改原变量,或避免大对象拷贝。其他情况传值更安全、更快、更清晰。
什么时候必须加 &?
加 & 的唯一目的,是让函数能写回你传进去的那个变量本身——不是副本。
- 想在函数里改结构体字段?比如
updateScore(&student, 95)—— 不加&,student在函数里只是拷贝,改了也白改 - 传一个大定长数组(如
[1024]byte)?用*[1024]byte避免整块内存复制,但前提是你要操作原数组,且明确依赖长度信息 - 调用
json.Unmarshal(data, &user)这类反序列化函数?接口强制要求*T,因为要往目标内存里填数据
常见错误:cannot take the address of 42、cannot take the address of m["k"]、cannot take the address of getValue()。根本原因是 & 只能作用于可寻址的具名变量,字面量、map value、临时返回值都不行。
什么时候传 *T 会反而变慢或出错?
基本类型(int、string、bool)和小结构体(比如只有 2–3 个字段)传值更快。传指针不仅多一次解引用,还引入 nil 检查负担,且语义上不必要。
-
func increment(n *int)改一个int?不如func increment(n int) int直接返回新值 - 给
func process(s []int)传&mySlice?编译失败——切片本身已是引用类型,传值就能改底层数组元素;加&反而变成*[]int,类型不匹配 - 声明
var p *int后直接写*p = 42?p是nil,运行时 panic:invalid memory address or nil pointer dereference
性能提示:结构体大小超过约 128 字节时,建议跑下 go build -gcflags="-m" 看逃逸分析;若频繁堆分配,再考虑传 *T。
方法接收者该用 T 还是 *T?
看方法要不要修改接收者字段。要改,就必须用 *T;只读,T 更轻量。
-
func (u *User) SetName(n string)→ 必须*User,否则改的是副本 -
func (u User) GetName() string→User就够,没副作用,调用开销更低 - 混用危险:如果已有某个方法用了
*User接收者,那User{}值变量就无法调用它(因不可寻址),而&User{}指针变量又不能调用GetName()(除非也改成*User)
工程建议:对可导出结构体,统一用 *T 接收者,避免接口实现割裂(如 io.Writer 要求 Write 方法必须能被指针调用)。
nil 指针解引用为什么必 panic?
Go 不做空指针防护,*p 在 p == nil 时直接崩溃。这不是 bug,是设计选择——强制你在逻辑关键路径显式检查。
- 函数返回
*User(如findUser(id))?调用后必须先if u != nil再解引用 - 用
reflect.ValueOf(ptr).Elem()前,得先确认ptr.Kind() == reflect.Ptr && !ptr.IsNil() -
sync/atomic.Pointer或unsafe操作时,编译器不会帮你拦住nil,出问题往往静默且难复现
最容易被忽略的一点:*T 类型本身不表示“可空”,它就是个地址;nil 不是零值,是未指向任何有效内存的状态。别把它当 Go 的 “nullable int” 用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











