Go language patterns for 2026 — concurrency with errgroup, error wrapping, HTTP servers, gRPC, database access, testing, and CLI with Cobra
面向 Go 1.24+ 的生产级 Go 模式,涵盖完整的开发生命周期。包括使用 errgroup 和 context 取消的惯用并发、使用 %w 的错误包装、使用 Chi 路由器的 HTTP 服务器、使用 pgx 的 PostgreSQL、gRPC 服务、表格驱动测试、使用 Cobra 的 CLI 工具以及使用 pprof 的性能分析。涵盖 Go 1.18+ 泛型、Go 1.22+ 整数范围迭代和 Go 1.23+ 迭代器。
安装此技能以获取生产就绪的 Go 模式,包括:
在 Go 项目开发中,此技能提供以下方面的上下文:
go
// 始终将 context 作为 I/O 函数的第一个参数
func FetchData(ctx context.Context, url string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, GET, url, nil)
if err != nil { return nil, err }
resp, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
// 调用者控制超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
data, err := FetchData(ctx, https://api.example.com/data)
go
func ProcessItems(ctx context.Context, items []string) error {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(5) // 限制最多 5 个并发 goroutine
for _, item := range items {
item := item // 捕获循环变量
g.Go(func() error {
return processOne(ctx, item)
})
}
return g.Wait() // 返回第一个错误
}
go
// 使用 %w 包装以保留错误链
func ReadConfig(path string) (Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return Config{}, fmt.Errorf(读取路径 %s 的配置: %w, path, err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf(解析配置: %w, err)
}
return cfg, nil
}
// errors.Is() 适用于包装的错误;== 不适用
if errors.Is(err, ErrNotFound) { ... }
// errors.As() 从链中提取自定义错误类型
var valErr *ValidationError
if errors.As(err, &valErr) {
fmt.Printf(无效字段: %s\n, valErr.Field)
}
myapp/
├── cmd/myapp/main.go # 入口点
├── internal/
│ ├── domain/ # 业务逻辑(未导出)
│ ├── service/ # 应用服务
│ ├── repository/ # 数据访问层
│ └── http/ # HTTP 处理器
├── pkg/ # 公共库
├── migrations/ # SQL 迁移文件
└── go.mod
internal/ 由 Go 编译器强制执行。永远不要创建 /src。
go
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RequestID)
r.Get(/, homeHandler)
r.Post(/users, createUserHandler)
r.Route(/api, func(r chi.Router) {
r.Use(authMiddleware)
r.Get(/profile, getProfileHandler)
})
http.ListenAndServe(:8080, r)
go
server := &http.Server{
Addr: :8080, Handler: setupRoutes(),
ReadTimeout: 5 time.Second, WriteTimeout: 5 time.Second,
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigChan
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
server.Shutdown(ctx)
}()
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf(服务器错误: %v, err)
}
go
config, _ := pgxpool.ParseConfig(postgres://user:pass@localhost/db)
config.MaxConns = 25
pool, err := pgxpool.NewWithConfig(context.Background(), config)
var id int; var name string
err = pool.QueryRow(ctx, SELECT id, name FROM users WHERE id = $1, 1).Scan(&id, &name)
if errors.Is(err, pgx.ErrNoRows) { fmt.Println(未找到) }
数据库选择:pgx 用于高性能原始 SQL,GORM 用于复杂关系,sqlc 用于从 SQL 注释生成类型安全的 Go 代码。
go
func TestAdd(t *testing.T) {
tests := []struct{ name string; a, b, expected int }{
{正数, 2, 3, 5},
{负数, -2, -3, -5},
{零, 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.expected {
t.Errorf(Add(%d, %d) = %d, 期望 %d, tt.a, tt.b, got, tt.expected)
}
})
}
}
go
type Database interface {
GetUser(ctx context.Context, id int) (User, error)
}
// 注入接口,而非具体类型
type UserService struct { db Database }
// 用于测试的模拟
type MockDB struct{}
func (m *MockDB) GetUser(ctx context.Context, id int) (User, error) {
return User{ID: id, Name: 模拟用户}, nil
}
go
var rootCmd = &cobra.Command{Use: myapp, Short: 我的应用程序}
var counterCmd = &cobra.Command{
Use: count, Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
max, _ := cmd.Flags().GetInt(max)
fmt.Printf(计数到 %d\n, max)
return nil
},
}
func init() {
rootCmd.AddCommand(counterCmd)
counterCmd.Flags().IntP(max, m, 10, 最大计数)
}
| 问题 | 解决方案 |
|---|---|
| Goroutine 泄漏(无法退出) | 在 goroutine 循环中添加 case <-ctx.Done(): return |
| range ch 永不退出 |
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 go-patterns-1776210045 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 go-patterns-1776210045 技能
skillhub install go-patterns-1776210045
文件大小: 3.84 KB | 发布时间: 2026-4-15 11:30