Go 的错误哲学
Go 无 exception:返回 error 作为值。调用方必须显式处理。
f, err := os.Open("config.toml")
if err != nil {
return fmt.Errorf("open config: %w", err)
}
defer f.Close()
自定义 error
type NotFoundError struct {
ID string
}
func (e *NotFoundError) Error() string {
return "not found: " + e.ID
}
Sentinel:var ErrNotFound = errors.New("not found")。
错误链
if err != nil {
return fmt.Errorf("service get user: %w", err)
}
if errors.Is(err, sql.ErrNoRows) { / ... / }
var nfe *NotFoundError
if errors.As(err, &nfe) { / use nfe.ID / }
面试强调:不要 _ = err 忽略;日志打 %+v 需 pkg/errors 或 zap 字段。
panic 与 recover
panic 用于 不可恢复编程错误;HTTP handler 最外层 recover 转 500。业务逻辑用 error,少用 panic。
testing 包
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"pos", 1, 2, 3},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Fatalf("got %d want %d", got, tt.want)
}
})
}
}
httptest 测 Handler;sqlmock 测 DB 层(interface 注入见 week02-go-struct-interface)。
benchmark
func BenchmarkParse(b *testing.B) {
data := loadFixture()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Parse(data)
}
}
-benchmem 看分配;对比优化前后 ns/op 与 allocs/op。
工程实践
- 错误信息:动词 + 对象 + 原因,带 context。
- 单元测试覆盖边界:nil、空 slice、并发(
-race)。 - CI:
go test ./... -race -count=1。
与后端面试
讲项目时说明:如何测试 RPC、如何 mock 依赖、线上 error 如何分级告警。
下一篇 week03-go-memory-gc 讲性能与 GC,与 benchmark 呼应。
多错误聚合与可观测性
Go 1.20+ 支持 errors.Join(errs ...error),适合并行校验多个字段失败时一次性返回。日志层应记录 error chain 全链路,便于 Sentry 等工具按根因分组。HTTP 层映射:4xx 业务可预期(参数错误),5xx 未预期(依赖超时)。可重试错误 应包装 sentinel ErrTemporary,调用方配合指数退避。
测试替身与集成测试
interface 注入 Repository 后,单测用 fake 内存实现;集成测用 testcontainers 起 MySQL/Redis。t.Parallel() 加速无共享状态的 case,共享全局 map 的测试禁止 parallel。-coverprofile 关注核心包覆盖率,但 100% 覆盖率不等于无 bug,重点覆盖分支与 error path。
面试追问示例
「线上 panic 如何处理?」→ 最外层 middleware recover,打 stack,返回统一 JSON,异步告警。「table-driven 如何测 error?」→ wantErr true + errors.Is 断言类型。结合 week02-go-struct-interface 的 mock 模式完整回答依赖隔离。
补充要点
t.Helper() 标记辅助函数;TestMain 做全局 setup。fuzzing Go 1.18+ 发现边界输入。mock 代码生成 mockgen;集成测试 tag build。CI 必须 -race。
错误处理反模式
切忌 if err != nil { log.Println(err) } 后继续执行,导致脏数据写入。切忌用 panic 控制业务流程。跨 goroutine 错误用 errgroup 收集第一个 error 并 cancel 兄弟任务。对外 API 不要把内部 stack 直接返回给用户,映射为业务 code 与 message,详细链写日志。
测试分层策略
单元测试覆盖纯函数与 domain 逻辑;集成测试验证 SQL 与 Redis 行为;端到端测试少量黄金路径。表驱动 case 命名应描述场景,如「空输入」「重复提交」。benchmark 对比优化前后 allocs,与 week03-go-memory-gc 联动。面试时主动说 CI 跑 race detector,发布前跑回归套件,体现工程规范。