指针变量存储的是地址而非值,&操作符获取变量内存地址,用于解引用访问或修改所指变量;p初始为nil,直接p会panic;*p与原变量等价但类型严格匹配;传指针实为地址拷贝,只能修改所指值不能改变指针本身。

指针变量存的是地址,不是值
Go里所有变量都有内存地址,&操作符就是用来拿到这个地址的。比如 x := 42,&x 返回的是一串类似 0xc00001a088 的十六进制数——它本身不是数据,而是数据在内存里的“门牌号”。声明一个指针变量,例如 var p *int,这时 p 的值就是这个门牌号,而不是 42。
容易踩的坑:
-
p初始值是nil,直接*p会 panic - 误把
p当成值来用(比如传给需要int的函数),编译器会报错:类型不匹配 - 打印
p得到的是地址,打印*p才得到值——两者类型完全不同
解引用 * 是访问“门牌号对应房间里的东西”
* 不是乘号,是“顺着地址找到那个变量”的动作。它只在两种场景出现:
- 右值位置:
v := *p→ 把p指向的变量的值读出来 - 左值位置:
*p = 100→ 把100写进p指向的变量所在内存位置
关键在于:*p 本质上就是原变量的别名。下面这段代码中,*p 和 x 完全等价:
立即学习“go语言免费学习笔记(深入)”;
x := 42 p := &x *p = 99 fmt.Println(x) // 输出 99
注意:*p 只有在 p 非 nil 且指向有效变量时才安全;如果 p 是 new(int) 或显式赋了地址,就没问题;但如果只是 var p *int 就去 *p,运行时直接崩溃。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
指针类型和所指变量类型必须严格匹配
*int 只能指向 int 变量,不能指向 int32 或 *int(即不能存“指针的地址”除非你定义 **int)。Go 不允许隐式转换,哪怕底层都是整数。
常见错误现象:
-
var i int32 = 1; p := &i→ 编译失败,&i类型是*int32,不能赋给*int - 结构体字段是
*string,却传入一个字符串字面量地址:&"hello"→ 字面量不可寻址,编译报错cannot take the address of "hello" - 想让指针指向局部变量,但该变量是函数返回的临时值(如 map 查找结果、切片元素),可能因逃逸分析失败或生命周期问题导致未定义行为
函数参数传指针时,真正传递的是地址拷贝
Go 始终是值传递。传指针,传的其实是那个“门牌号”的副本。所以函数内修改 *p,会影响原变量;但若在函数里让 p 指向新地址(比如 p = &y),这个改变不会回到调用方。
典型误区:
- 以为“传指针就能让函数改掉指针本身”,其实只能改它指向的值
- 对大结构体传值开销大,就盲目全改成指针——但小结构体(如两个
int)传值反而更快,指针多一次内存跳转 - 并发场景下多个 goroutine 共享同一指针,没加锁就改
*p,引发竞态(race condition)
真正要小心的,从来不是“怎么写指针”,而是“谁在什么时候持有它的地址、是否可变、是否线程安全”。地址本身很轻,出问题的永远是背后那块内存的归属和访问方式。

















