Go中指针是存储内存地址的普通变量,有类型、值和固定大小,非引用或别名;&x仅对可寻址对象有效;*T与T类型不同,不可隐式转换;nil是合法零值,解引用前须判空;指针影响逃逸分析与内存布局。

Go 中的指针变量不是“指向变量的引用”,而是**存储另一个变量内存地址的普通变量**——它本身有类型、有值(地址)、占 4 或 8 字节,和 int 或 string 一样是第一等公民。
指针变量的值就是内存地址,不是“别名”也不是“链接”
很多人误以为 p := &x 是让 p “变成 x 的另一个名字”,其实不是。p 是一个独立变量,它的值恰好是 x 在内存中的起始地址(比如 0xc0000140a8)。你可以打印它、赋给另一个指针、传进函数,但它不自动同步 x 的生命周期或绑定语义。
-
&x只对可寻址对象有效:变量、结构体字段、切片元素 ——&42、&fmt.Sprintf("a")都非法 -
p本身的值可以被修改(比如p = &y),这不会影响x;只有*p = v才真正写入x所在的内存位置 - 指针变量也参与逃逸分析:如果它被返回或长期持有,
x很可能被分配到堆上,而非函数栈中
*T 和 T 是完全不同的类型,不能隐式转换
*int 不是 int 的“加强版”,它是独立类型,和 int 没有赋值兼容性。编译器会严格检查:
-
var x int = 5; var p *int = x→ 编译错误:cannot use x (type int) as type *int - 必须显式取地址:
p = &x,因为&x的类型才是*int - 同理,
*p的类型是int,不是*int;解引用后得到的是值,不是指针
nil 指针不是“空值”,而是未初始化的地址零值
var p *int 声明后,p == nil 是 true,但这不代表“没用”或“该报错”。nil 是合法状态,常用于表达“可选”或“未设置”:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- JSON 序列化时,
Age *int字段为 nil → 输出"age": null;若为Age int→ 输出"age": 0,语义完全不同 - 函数参数接受
*string时,调用方传nil是常见且预期的行为(例如表示“跳过该字段”) - 解引用前不判空:
if p != nil { fmt.Println(*p) }—— 忘了这一步,panic: invalid memory address or nil pointer dereference立刻发生
指针变量本身也占内存,且可能逃逸
指针变量不是轻量魔法标签,它自身也要被分配空间(64 位系统占 8 字节),并且它的存在会影响编译器对所指向变量的内存布局决策:
-
func f() *int { x := 42; return &x }→x必须逃逸到堆,否则返回栈地址会导致悬空指针(Go 编译器会自动处理,但你要理解代价) - 频繁取地址 + 返回指针,可能增加 GC 压力;小类型(如
int、bool)通常没必要传指针,值传递更高效 - 结构体方法接收者用指针(
func (p *MyStruct) Foo())不只是为了修改字段,更是为了避免每次调用都复制整个结构体
真正难的不是语法,是判断“这个变量是否需要暴露地址”——它是否会被跨作用域使用?是否需被修改?是否足够大?是否参与 JSON/DB 映射?这些决策比写 & 和 * 更关键。

















