关于 go-ops
面向 Go 开发的参考技能,涵盖惯用写法、并发、测试、项目结构和性能,为开发者提供速查内容与专题资料。
主要功能
- 01惯用 Go 写法与错误处理
- 02并发模式与指导
- 03接口与泛型
- 04测试与项目结构
- 05性能分析与优化实践
适用场景
- 01选择错误处理方式
- 02设计并发 Go 任务
- 03规划 Go 项目包结构
- 04测试或分析 Go 项目性能
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill go-ops安装后在 Claude Code 中输入/go-ops确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/.gitkeepreferences/concurrency.mderror-handling.mdexpert-insights.mdinterfaces-generics.mdperformance.mdproject-structure.mdtesting.mdscripts/.gitkeep详细介绍
Go 运维
全面的 Go 技能,涵盖惯用模式、并发和生产实践。
模块快速入门
# New module
go mod init github.com/user/project
# Add dependency
go get github.com/lib/pq@latest
# Tidy (remove unused, add missing)
go mod tidy
# Vendor dependencies
go mod vendor
# Workspace (multi-module)
go work init ./api ./shared
go work use ./cli
错误处理决策树
What kind of error?
│
├─ Known, expected condition (e.g. "not found")
│ └─ Sentinel error: var ErrNotFound = errors.New("not found")
│ └─ Caller checks: errors.Is(err, ErrNotFound)
│
├─ Need to carry structured data (status code, field name)
│ └─ Custom error type: type ValidationError struct { Field, Message string }
│ └─ Implement Error() string
│ └─ Caller checks: errors.As(err, &validErr)
│
├─ Adding context to an existing error
│ └─ Wrap: fmt.Errorf("load config: %w", err)
│ └─ Preserves original for Is/As checks
│
├─ Truly unrecoverable (corrupted state, programmer bug)
│ └─ panic("invariant violated: ...")
│ └─ Almost never in library code
│
└─ Multiple errors from concurrent work
└─ errors.Join(err1, err2) or multierr package
错误包装约定
// Add context at each layer, don't repeat the function name
func LoadUser(id int) (*User, error) {
row, err := db.Query("SELECT ...", id)
if err != nil {
return nil, fmt.Errorf("load user %d: %w", id, err)
}
// ...
}
并发决策树
What's the concurrency pattern?
│
├─ Run N independent tasks, collect results
│ └─ errgroup.Group (cancels on first error)
│
├─ Fire-and-forget background work
│ └─ go func() with context for cancellation
│ └─ ALWAYS handle the error or log it
│
├─ Producer/consumer pipeline
│ └─ Channels (buffered for throughput)
│ └─ Close channel when producer is done
│
├─ Rate-limited concurrent work
│ └─ Semaphore: make(chan struct{}, maxConcurrency)
│
├─ Shared mutable state
│ └─ sync.Mutex or sync.RWMutex
│ └─ Prefer channels if the state is simple
│
├─ One-time initialization
│ └─ sync.Once
│
└─ Wait for N goroutines to finish (no error collection)
└─ sync.WaitGroup
errgroup 快速入门
import "golang.org/x/sync/errgroup"
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10) // max 10 concurrent goroutines
for _, url := range urls {
g.Go(func() error {
return fetch(ctx, url)
})
}
if err := g.Wait(); err != nil {
return fmt.Errorf("fetch urls: %w", err)
}
深入了解:加载 ./references/concurrency.md,了解工作池、扇出/扇入、流水线模式和 context 最佳实践。
接口设计
Accept interfaces, return structs.
// Good: function accepts interface
func Process(r io.Reader) error { ... }
// Good: return concrete type
func NewServer(cfg Config) *Server { ... }
// Bad: returning interface (hides implementation, prevents extension)
func NewServer(cfg Config) ServerInterface { ... }
常见标准库接口
| 接口 | 方法 | 用途 |
|---|---|---|
io.Reader | Read([]byte) (int, error) | 任意字节源 |
io.Writer | Write([]byte) (int, error) | 任意字节接收端 |
io.Closer | Close() error | 资源清理 |
fmt.Stringer | String() string | 字符串表示 |
error | Error() string | 错误值 |
sort.Interface | Len, Less, Swap | 自定义排序 |
http.Handler | ServeHTTP(w, r) | HTTP 处理器 |
encoding.BinaryMarshaler | MarshalBinary() ([]byte, error) | 二进制编码 |
函数式选项模式
type Option func(*Server)
func WithPort(port int) Option {
return func(s *Server) { s.port = port }
}
func WithTimeout(d time.Duration) Option {
return func(s *Server) { s.timeout = d }
}
func NewServer(opts ...Option) *Server {
s := &Server{port: 8080, timeout: 30 * time.Second} // defaults
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
srv := NewServer(WithPort(9090), WithTimeout(5*time.Second))
深入了解:加载 ./references/interfaces-generics.md,了解泛型、类型约束、嵌入和类型断言。
测试快速参考
// Table-driven test
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 1, 2, 3},
{"zero", 0, 0, 0},
{"negative", -1, -2, -3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.expected {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
}
})
}
}
# Run tests
go test ./...
# With coverage
go test -cover -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific test
go test -run TestAdd ./pkg/math/
# Benchmarks
go test -bench=. -benchmem ./...
# Race detector
go test -race ./...
# Fuzz testing
go test -fuzz=FuzzParse ./...
深入了解:加载 ./references/testing.md,了解使用接口进行模拟、httptest、testcontainers 和黄金文件。
常见陷阱
| 陷阱 | 原因 | 修复方法 |
|---|---|---|
| nil 切片与空切片 | var s []int 为 nil,s := []int{} 为空。json.Marshal 分别生成 null 和 [] | 如果 JSON 结果很重要,请使用 make([]int, 0) 或 []int{} |
| Goroutine 泄漏 | Goroutine 阻塞在没有读写方的通道上 | 使用 context.WithCancel,始终提供退出路径 |
| 循环中的 defer | 延迟调用要等函数返回后才会执行 | 将循环体包装在闭包中,或使用显式清理 |
| 接口 nil 陷阱 | 将 (*MyType)(nil) 赋给 error 接口后,它不等于 nil | 显式返回 nil,不要返回类型化的 nil 指针 |
| Range 变量捕获 | 循环变量会被重复使用(Go 1.22 之前) | 使用 go func(v T) { ... }(v),或升级到 Go 1.22+ |
| 循环中进行字符串拼接 | O(n^2) 次分配 | 使用 strings.Builder |
在 Go 之后调用 sync.WaitGroup 的 Add | 竞态条件 | 在 go func() 之前调用 wg.Add(1) |
| 无缓冲通道死锁 | 发送和接收必须并发发生 | 使用带缓冲的通道或独立的 Goroutine |
map 不支持并发安全使用 | 竞态条件,可能崩溃 | 使用 sync.Mutex 或 sync.Map |
项目结构
project/
├── cmd/
│ ├── api/main.go # Entry points
│ └── worker/main.go
├── internal/ # Private packages
│ ├── handler/
│ ├── service/
│ └── repository/
├── pkg/ # Public packages (optional)
├── go.mod
├── go.sum
├── Makefile # or justfile
└── .golangci.yml
深入了解:加载 ./references/project-structure.md,了解工作区模式、构建标签、ldflags 和 lint 配置。
性能快速参考
# CPU profile
go test -cpuprofile=cpu.prof -bench=. ./...
go tool pprof cpu.prof
# Memory profile
go test -memprofile=mem.prof -bench=. ./...
go tool pprof -alloc_space mem.prof
# Trace
go test -trace=trace.out ./...
go tool trace trace.out
# Escape analysis
go build -gcflags='-m' ./...
| 优化 | 适用场景 | 模式 |
|---|---|---|
| 预分配切片 | 大小已知 | make([]T, 0, n) |
strings.Builder | 字符串拼接 | var b strings.Builder |
sync.Pool | 频繁分配和释放同一类型 | pool.Get() / pool.Put() |
| 结构体字段对齐 | 对内存敏感 | 按大小分组字段(从大到小) |
| 缓冲区复用 | I/O 密集型 | bufio.NewReaderSize(r, 64*1024) |
深入了解:加载 ./references/performance.md,了解 pprof 使用指南、基准测试模式和逃逸分析。
参考文件
深入了解相关主题时,请加载这些文件。每个文件均可独立使用。
| 参考文件 | 加载时机 |
|---|---|
./references/concurrency.md | Goroutine、通道、上下文、同步原语、工作池、流水线 |
./references/error-handling.md | 错误包装、哨兵错误、自定义类型、多错误、panic/recover |
./references/testing.md | 表驱动测试、模拟、httptest、基准测试、模糊测试、testcontainers、黄金文件 |
./references/interfaces-generics.md | 接口设计、嵌入、类型断言、泛型、类型约束 |
./references/project-structure.md | 标准目录布局、go.mod、工作区、构建标签、ldflags、golangci-lint |
./references/performance.md | pprof、trace、基准测试、逃逸分析、sync.Pool、结构体对齐 |
./references/expert-insights.md | HTTP 服务端(Go 1.22 路由)、优雅关闭、http.Client 调优、JSON 辅助函数 |
另请参阅
docker-ops- Go 二进制文件的多阶段构建(scratch/distroless)ci-cd-ops- Go CI 流水线、缓存 Go 模块、goreleasertesting-ops- 跨语言测试策略
评论
支持 Markdown