该用指针仅当需修改原值或避免拷贝大对象(>16字节struct、slice等);小类型如int、string、小struct直接传值更清晰安全,sync.Mutex等不可拷贝类型必须用指针。

什么时候该用指针,什么时候不该用
Go 里传值成本低的类型(int、string、struct{a,b int} 等小结构体)根本不需要指针——编译器会内联或优化,强行加 * 反而干扰语义。只有两类情况才真正需要指针:需要修改原值,或避免拷贝大对象(比如 >16 字节的 struct、slice、map、channel 本身虽是引用类型但不需额外取地址)。
常见误用:给 string 或 int 加指针只为了“统一接口”,结果调用方得写 &x,被调用方还得判空,纯属自找麻烦。
- 小结构体(字段总和 ≤ 机器字长)直接传值,清晰且无性能损失
-
sync.Mutex必须取地址——它内部有不可拷贝字段,复制会导致 panic - 方法接收者用指针,仅当方法内要修改 receiver 字段;否则用值接收者更安全、更易测试
接口参数中混用指针和值带来的可读性陷阱
函数签名里同时出现 *T 和 T 参数,会让调用方反复确认:“这个要不要取地址?那个是不是已经是指针了?”尤其当 T 是自定义类型时,容易传错。
例如:func Process(user *User, config Config, logger *zap.Logger) —— user 和 logger 都是指针,config 却是值,但 Config 实际可能有 20 个字段。这时要么全值(如果 Config 不大),要么全指针(如果确实要避免拷贝),别混着来。
立即学习“go语言免费学习笔记(深入)”;
- 同一函数内,相同语义的参数保持一致:都传值,或都传指针
- 如果某个参数是配置类结构体,且字段较多或未来可能膨胀,一开始就定义为
*Config,并在文档里说明“不可 nil” - 避免在参数里暴露实现细节:比如本该接收
io.Reader,却写成*bytes.Buffer
nil 检查泛滥是过度使用指针的典型副作用
一旦你把一个本可传值的参数改成 *T,就得面对 “is it nil?” 的问题。每个函数入口加 if x == nil { return err },不仅冗余,还掩盖了设计问题——为什么调用方能传 nil?是不是本该由构造函数/工厂保证非空?
典型例子:func NewService(cfg *Config) *Service。如果 Config 是必需的,就该强制传非空值:func NewService(cfg Config) *Service,或者用选项模式:NewService(WithTimeout(30))。
- 所有导出函数的指针参数,必须在 godoc 注释里明确写清 “nil is not allowed” 或 “nil is valid”
- 对内部函数,优先用值类型;若必须用指针,考虑用
assert或单元测试覆盖 nil 场景,而不是在每处加 guard - 用 go vet 检查
nildereference,但它不会提醒你“这里其实不该用指针”
嵌套结构体中指针字段的隐蔽成本
结构体里大量用 *string、*int 来支持“可选字段”,看似灵活,实则让 JSON 解析、数据库映射、日志打印全都变复杂。比如 type User { Name *string `json:"name,omitempty"` },你得先初始化 u := &User{}; u.Name = new(string); *u.Name = "Alice",比直接用 string 多三步。
更糟的是,这类字段让零值判断变得模糊:u.Name == nil 表示未设置,*u.Name == "" 表示设为空字符串——但很多业务逻辑根本不区分这两者。
- 除非明确需要区分“未设置”和“设为空”,否则用值类型 + 零值语义(如空字符串、0、false)更直白
- API 结构体需兼容缺失字段?用
omitemptytag 配合值类型即可,不用指针 - 数据库 ORM(如 GORM)对
*T字段默认忽略零值更新,容易引发意外跳过字段更新,不如显式用db.Select("name").Updates(&u)
type Config struct {
Timeout int `json:"timeout"` // 值类型,0 表示默认
LogPath string `json:"log_path,omitempty"` // 空字符串即不写入 JSON
// ❌ 避免:LogPath *string `json:"log_path,omitempty"`
}
指针不是银弹,它是明确的契约:我要改你,或我不能拷贝你。滥用它,代码就从“说了算”变成“猜着看”。










