Go中用指针只为修改原变量或避免大对象拷贝;必须加&的情况是需函数修改原变量本身,如updateScore(&student,95),而字面量、map值等不可取地址。

Go 语言里用指针,核心就一条:**想改原变量,或避免大对象拷贝,才用;否则按值传更安全、更直白。**
什么时候必须加 &?什么时候加了反而错?
加 & 的唯一目的,是让函数能修改你传进去的那个变量本身——不是副本。
- 想在函数里改
struct字段?比如updateScore(&student, 95)—— 必须加&,否则student在函数里只是拷贝,改了也白改 - 传一个大数组(比如
[1024]int)?用*[1024]int比传值省空间,但得确认你真要操作原数组,而不是转成切片处理 - 对字面量、常量、map value、函数返回值,不能加
&:&42、&m["k"]、&foo()全部编译报错:cannot take the address of ... - 切片、map、channel 本身已是引用类型,传它们不用加
&;加了反而多一层间接,还容易误以为能改底层数组头(其实不能直接改len/cap)
*T 声明和 *p 解引用,根本不是一回事
声明里的 * 是告诉编译器“这变量存地址”,运行时没动作;表达式里的 * 是真实去内存读/写,会 panic 如果指针是 nil。
-
var p *int只是声明,p值为nil;此时写*p = 42直接 panic:invalid memory address or nil pointer dereference - 必须先让它指向有效内存:
p = &x或p = new(int)(后者等价于var x int; p = &x) -
new(T)返回的是*T,不是T;make([]T, n)返回的是[]T,不是*[]T - 别把
*int当成“可空的 int”——它就是个地址,nil不代表“零值”,代表“没指向任何地方”
原子指针操作 sync/atomic.Pointer 的硬约束
它只做一件事:安全地替换一个 unsafe.Pointer,不带锁、无 GC 跟踪,但代价是所有细节都得你手动兜底。
立即学习“go语言免费学习笔记(深入)”;
- 存之前必须显式转换:
p.Store(unsafe.Pointer(&x)),不能直接p.Store(&x)(类型不匹配) - 取出来必须判
nil再强转:if ptr := p.Load(); ptr != nil { config := (*Config)(ptr) },否则 panic - 千万别缓存转换后的
*Config指针——下一次Load()可能已指向新对象,旧指针变悬垂 - 如果指针指向的是切片首元素,别用
&slice[0];扩容后地址失效,要用unsafe.Slice(&x, 1)配合固定分配的底层数组 -
unsafe.Pointer不受 GC 保护,若指向 Go 分配的对象,又没其他强引用,可能被提前回收
指针最麻烦的地方不在语法,而在生命周期和所有权——谁分配、谁释放、谁保证地址一直有效。尤其是混用 unsafe 和原子操作时,编译器不会帮你检查,出问题往往静默且难复现。


















