一、指针 vs 值传递(核心原则)
✅ 判断规则
1. 需要修改数据 → 用指针
2. 对象很大 → 用指针
3. 小对象 + 只读 → 用值(推荐)
4. 方法接收者一致 → 保持一致
❌ 常见误区
func distance(p *Point) {} // ❌ 不必要的指针
问题:
增加 nil 风险
语义误导(看起来会修改)
可能增加 GC 压力
✅ 推荐写法
func distance(p Point) {} // ✅
二、interface 使用原则
1️⃣ 不要使用 *interface(反模式)
func f(w *io.Writer) {} // ❌
原因:
interface 本身已是引用语义
增加一层间接访问,没有收益
破坏抽象
2️⃣ interface 的本质
interface = (type, data pointer)
👉 已经包含指针语义
三、nil 设计与风险控制
核心原则
不要让 nil 在系统中“流动”
✅ 正确做法
1️⃣ 构造函数保证非 nil
func NewUser() *User {
return &User{}
}
2️⃣ 边界检查(而不是内部检查)
func Handle(u *User) error {
if u == nil {
return errors.New("nil user")
}
return u.do()
}
3️⃣ 小对象优先值传递
func Process(p Point) {} // 永远不会 nil
❌ 错误做法
func (u *User) Save() {
if u == nil { // ❌ 到处防御
return
}
}
四、interface “假 nil”陷阱(高危)
现象
var e *MyError = nil
var err error = e
fmt.Println(err == nil) // false ❗
原因
err = (type: *MyError, data: nil)
👉 interface 判断 nil 要求:
type == nil && data == nil
✅ 规避方法
if e == nil {
return nil // ✅
}
return e
五、error wrapping(错误链)
❌ 错误写法
return fmt.Errorf("failed: %v", err) // ❌
👉 丢失错误链
✅ 正确写法
return fmt.Errorf("failed: %w", err) // ✅
使用方式
if errors.Is(err, target) { }
自定义 error 必须实现
func (e *MyError) Unwrap() error {
return e.Err
}
六、error 判断原则
| 场景 | 推荐 |
|---|---|
| 判断具体错误 | errors.Is |
| 类型断言 | errors.As |
| 直接比较 | ❌ 避免 |
七、context 使用原则
1️⃣ context 是“控制器”,不是“数据容器”
用于:
- 超时控制
- 取消传播
2️⃣ 必须向下传递
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
do(ctx)
}
3️⃣ goroutine 必须绑定 ctx
go func(ctx context.Context) {
select {
case <-ctx.Done():
return
}
}(ctx)
八、HTTP / Shutdown 关键点
核心理解
signal → ctx → Shutdown
Shutdown 行为
停止接收新请求
等待已有请求完成
超时后强制关闭
❌ 常见误解
Shutdown 会监听系统信号 ❌
实际:
只监听 ctx
九、接口 vs 结构体设计哲学
| 类型 | 作用 |
|---|---|
| struct | 表达数据 |
| interface | 表达行为 |
net/http 示例
func handler(w http.ResponseWriter, r *http.Request)
r:数据(大对象 → 指针)w:行为(接口)
十、工程实践总结(最重要)
一句话原则
1. 用语义决定指针还是值,不要机械统一
2. interface 不要加指针
3. nil 不要在系统中传播
4. error 必须支持 unwrap
5. ctx 必须贯穿调用链
最容易踩的三个坑
1. interface != nil 但内部是 nil
2. error wrapping 用了 %v 而不是 %w
3. 所有 struct 都用指针(过度设计)
结尾
这套规则本质上围绕三件事:
- 可读性(语义清晰)
- 可控性(避免隐式行为)
- 可维护性(错误可追踪)