忽略错误
错误:使用 _ 忽略错误 正确:处理或记录每个错误
来源: everything-claude-code 技能库
golang-patterns 涵盖 Go 语言的惯用语模式、最佳实践和约定,用于构建健壮、高效和可维护的应用。
Go 偏向简洁而非巧妙。代码应该显而易见、易于阅读:
// 好:清晰直接func GetUser(id string) (*User, error) { user, err := db.FindUser(id) if err != nil { return nil, fmt.Errorf("get user %s: %w", id, err) } return user, nil}
// 不好:过度巧妙func GetUser(id string) (*User, error) { return func() (*User, error) { if u, e := db.FindUser(id); e == nil { return u, nil } else { return nil, e } }()}设计类型时,让零值无需初始化即可使用:
// 好:零值就有用var mu sync.Mutex // 无需初始化即可使用var ch chan int // 无需 make 即可使用var m map[string]int // 零值是 nil,但读取安全
// 不好:需要显式初始化mu := &sync.Mutex{} // 不必要Go 没有继承,使用组合代替:
// 好:组合type Reader struct { io.Reader logger Logger}
// 不好:模拟继承type Reader struct { io.Reader // 这不是继承,只是嵌入}Go 没有异常,错误是返回值:
// 好:显式错误处理func ReadFile(path string) ([]byte, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read file %s: %w", path, err) } return data, nil}
// 不好:忽略错误data, _ := os.ReadFile(path) // 错误被忽略!func ReadConfig(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config: %w", err) }
var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parsing config: %w", err) }
return &cfg, nil}func FetchUser(ctx context.Context, id string) (*User, error) { req, err := http.NewRequestWithContext(ctx, "GET", "/users/"+id, nil) if err != nil { return nil, err }
resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
// ...}func fetchAll(urls []string) []Result { results := make([]Result, len(urls)) var wg sync.WaitGroup
for i, url := range urls { wg.Add(1) go func(i int, url string) { defer wg.Done() results[i] = fetch(url) }(i, url) }
wg.Wait() return results}type Cache struct { mu sync.RWMutex items map[string]interface{}}
func (c *Cache) Get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() val, ok := c.items[key] return val, ok}
func (c *Cache) Set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = value}type QueryBuilder struct { query strings.Builder params []interface{}}
func NewQueryBuilder() *QueryBuilder { return &QueryBuilder{ params: make([]interface{}, 0), }}
func (qb *QueryBuilder) Select(fields ...string) *QueryBuilder { qb.query.WriteString("SELECT ") qb.query.WriteString(strings.Join(fields, ", ")) return qb}
func (qb *QueryBuilder) From(table string) *QueryBuilder { qb.query.WriteString(" FROM ") qb.query.WriteString(table) return qb}
func (qb *QueryBuilder) Build() (string, []interface{}) { return qb.query.String(), qb.params}type Server struct { addr string port int maxConns int readTimeout time.Duration writeTimeout time.Duration}
type Option func(*Server)
func Addr(addr string) Option { return func(s *Server) { s.addr = addr }}
func Port(port int) Option { return func(s *Server) { s.port = port }}
func NewServer(opts ...Option) *Server { s := &Server{ addr: "localhost", port: 8080, } for _, opt := range opts { opt(s) } return s}
// 使用server := NewServer(Addr("0.0.0.0"), Port(9090))✅ 正确做法:1. 返回错误而非忽略2. 使用 %w 包装错误3. 提供有意义的错误信息4. 适当处理上游错误
❌ 错误做法:1. 使用 _ 忽略错误2. 返回裸错误3. 错误信息不清晰✅ 正确做法:1. 使用 sync.Mutex 保护共享数据2. 使用 channel 进行通信3. 使用 context 取消操作4. 注意 race condition
❌ 错误做法:1. 全局变量不加锁2. channel 和 mutex 混用3. 不检查 context 取消✅ 正确做法:1. 小接口,专注单一职责2. 依赖接口而非具体实现3. 接口放在需要的地方4. 避免不必要的接口
❌ 错误做法:1. 大而全的接口2. 过度抽象3. 接口定义过早# 格式化代码go fmt .gofmt -w .
# 代码检查go vet ./...golint ./...staticcheck ./...
# 依赖管理go mod tidygo mod download
# 测试go test -v ./...go test -race ./...go test -coverprofile=coverage.out
# 构建go build -o appgo build -ldflags="-s -w" app
# 文档go doc fmtgo doc -all忽略错误
错误:使用 _ 忽略错误 正确:处理或记录每个错误
全局变量
错误:使用全局共享变量 正确:使用依赖注入
过度并发
错误:创建过多 goroutine 正确:使用 worker pool 或 semaphore
不使用 context
错误:不传递 context 正确:context 用于取消和超时
何时使用
何时不用
关键要点
常见错误
| 技能 | 关系 |
|---|---|
| golang-testing | Go 测试 |
| code-review | 代码审查 |
| tdd-workflow | TDD 工作流 |
go mod initgo test -race ./...go vet ./...go fmt ./官方原文: golang-patterns SKILL.md
💡 提示:Go 的哲学是「少即是多」,写更少的代码,做更多的事。