指针是存储地址的变量,Go中只有值传递,传指针即传地址值;必须用指针的两种场景是修改原值和避免大对象拷贝;结构体方法接收者选* T还是T取决于是否修改字段及接口一致性。

指针就是存地址的变量,不是值本身
Go 里没有“引用传递”,只有值传递;但你可以传一个「地址的值」——这就是指针。它不神秘,就是一个占 4 或 8 字节的变量,里面存着另一个变量在内存里的位置。
-
&只能作用于**变量**(比如&x),不能对字面量用(&42、&"hello"都报错) -
*在声明时是类型修饰符(var p *int),在使用时是解引用(*p = 10)——上下文决定含义 - 未初始化的指针默认是
nil,直接fmt.Println(*p)就 panic
什么时候必须用指针?看两个硬需求
传指针不是为了“高级”,而是解决两个具体问题:改原值,或省拷贝。
- 需要修改调用方的数据 → 比如
func increment(p *int) { *p++ },不传*int就改不动main里的变量 - 避免大对象复制 → 结构体含
[]byte、map[string]interface{}或字段超过 3–4 个时,传*User比User快得多也安全得多 - 基础类型(
int、string、小 struct)传指针反而拖慢性能,还多一层nil判断负担
结构体方法接收者选 *T 还是 T?别猜,看行为
这不是风格问题,是语义和接口兼容性问题。
- 要改字段(
SetName、Reset)→ 必须用func (u *User) SetName(n string) - 只读计算(
FullName()、IsValid())→func (u User) FullName()更轻量、更安全 - 只要有一个方法用了
*User接收者,那所有方法最好统一用*User,否则User值类型无法满足含指针方法的接口
最容易踩的三个坑,都在循环和返回值里
这些错误不会编译失败,但运行时出问题,而且极难 debug。
立即学习“go语言免费学习笔记(深入)”;
- 循环中取局部变量地址:
for _, name := range names { u := User{Name: name}; m[name] = &u }→ 所有 key 都指向最后一次迭代的u - 正确写法是:
m[name] = &User{Name: name}(Go 逃逸分析自动分配到堆,每个都是独立地址) - 函数返回局部变量地址:
func bad() *int { v := 42; return &v }→ Go 编译器会捕获并报错,但类似逻辑(比如闭包捕获循环变量)仍可能漏掉
指针本身很简单,难的是判断「该不该用」和「用得对不对」——尤其是当多个 goroutine 共享一个 *Config 时,是否加锁、是否深拷贝、是否允许并发写,这些才是真实项目里卡住人的地方。










