返回顶部
g

golang-design-patternsGo设计模式

Idiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, and streaming. Apply when designing Go APIs, structuring applications, choosing between patterns, making design decisions, architectural choices, or production hardening.

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.1.2
安全检测
已通过
254
下载量
免费
免费
1
收藏
概述
安装方式
版本历史

golang-design-patterns

角色定位: 你是一位重视简洁与明确的 Go 架构师。你仅在模式能解决实际问题时才应用它——而非为了展示技巧——并且你会抵制过早的抽象。

模式:

  • - 设计模式 — 创建新的 API、包或应用结构:在提出模式之前,先询问开发者的架构偏好;优先选择能满足需求的最小模式。
  • 审查模式 — 审计现有代码的设计问题:扫描 init() 的滥用、无界资源、缺失超时以及隐式全局状态;在建议重构之前先报告发现的问题。

社区默认规则。 明确取代 samber/cc-skills-golang@golang-design-patterns 技能的公司技能具有优先权。

Go 设计模式与惯用法

面向生产级代码的惯用 Go 模式。关于错误处理的详细信息,请参阅 samber/cc-skills-golang@golang-error-handling 技能;关于上下文传播,请参阅 samber/cc-skills-golang@golang-context 技能;关于结构体/接口设计,请参阅 samber/cc-skills-golang@golang-structs-interfaces 技能。

最佳实践总结

  1. 1. 构造函数应使用函数选项模式——它们在 API 演进时扩展性更好(每个选项一个函数,无破坏性变更)
  2. 如果验证可能失败,函数选项必须返回一个错误——在构造时捕获错误配置,而非运行时
  3. 避免使用 init()——它隐式运行,无法返回错误,使测试不可预测。应使用显式构造函数
  4. 枚举应从 1 开始(或将 Unknown 哨兵值设为 0)——Go 的零值会静默地作为第一个枚举成员传递
  5. 错误情况必须优先处理并提前返回——保持正常路径平坦
  6. Panic 用于处理 bug,而非预期错误——调用者可以处理返回的错误;panic 会导致进程崩溃
  7. 在打开资源后立即 defer Close()——后续的代码变更可能意外跳过清理
  8. 使用 runtime.AddCleanup 而非 runtime.SetFinalizer——终结器不可预测且可能复活对象
  9. 每个外部调用都应设置超时——上游服务缓慢会无限期挂起你的 goroutine
  10. 限制一切(池大小、队列深度、缓冲区)——无界资源会不断增长直至崩溃
  11. 重试逻辑必须在尝试之间检查上下文取消
  12. 在循环中使用 strings.Builder 进行字符串拼接 → 参见 samber/cc-skills-golang@golang-code-style
  13. string 与 []byte:可变和 I/O 操作使用 []byte,显示和键使用 string——转换会分配内存
  14. 迭代器(Go 1.23+):用于惰性求值——避免将所有内容加载到内存中
  15. 流式传输大型数据——加载数百万行会导致 OOM;流式传输保持内存恒定
  16. 使用 //go:embed 处理静态资源——在编译时嵌入,消除运行时文件 I/O 错误
  17. 密钥/令牌使用 crypto/rand——math/rand 是可预测的 → 参见 samber/cc-skills-golang@golang-security
  18. 正则表达式必须在包级别编译一次——编译是 O(n) 复杂度且会分配内存
  19. 编译时接口检查:var _ Interface = (*Type)(nil)
  20. 少量重写代码 > 大型依赖——每个依赖项都会增加攻击面和维护负担
  21. 为可测试性设计——接受接口,注入依赖

构造函数模式:函数选项 vs 构建器

函数选项(首选)

go
type Server struct {
addr string
readTimeout time.Duration
writeTimeout time.Duration
maxConns int
}

type Option func(*Server)

func WithReadTimeout(d time.Duration) Option {
return func(s *Server) { s.readTimeout = d }
}

func WithWriteTimeout(d time.Duration) Option {
return func(s *Server) { s.writeTimeout = d }
}

func WithMaxConns(n int) Option {
return func(s *Server) { s.maxConns = n }
}

func NewServer(addr string, opts ...Option) *Server {
// 默认选项
s := &Server{
addr: addr,
readTimeout: 5 * time.Second,
writeTimeout: 10 * time.Second,
maxConns: 100,
}
for _, opt := range opts {
opt(s)
}
return s
}

// 使用方式
srv := NewServer(:8080,
WithReadTimeout(30*time.Second),
WithMaxConns(500),
)

构造函数应使用函数选项模式——它们在 API 演进时扩展性更好且代码量更少。仅当需要在配置步骤之间进行复杂验证时才使用构建器模式。

构造函数与初始化

避免使用 init() 和可变全局变量

init() 隐式运行,使测试更困难,并创建隐藏依赖:

  • - 多个 init() 函数按声明顺序运行,跨文件时按文件名字母顺序——脆弱
  • 无法返回错误——失败必须 panic 或 log.Fatal
  • 在 main() 和测试之前运行——副作用使测试不可预测

go
// 糟糕——隐藏的全局状态
var db *sql.DB

func init() {
var err error
db, err = sql.Open(postgres, os.Getenv(DATABASE_URL))
if err != nil {
log.Fatal(err)
}
}

// 良好——显式初始化,可注入
func NewUserRepository(db sql.DB) UserRepository {
return &UserRepository{db: db}
}

枚举:从 1 开始

零值应表示无效/未设置状态:

go
type Status int

const (
StatusUnknown Status = iota // 0 = 无效/未设置
StatusActive // 1
StatusInactive // 2
StatusSuspended // 3
)

编译一次正则表达式

go
// 良好——在包级别编译一次
var emailRegex = regexp.MustCompile(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)

func ValidateEmail(email string) bool {
return emailRegex.MatchString(email)
}

使用 //go:embed 处理静态资源

go
import embed

//go:embed templates/*
var templateFS embed.FS

//go:embed version.txt
var version string

编译时接口检查

→ 关于 var _ Interface = (*Type)(nil) 模式,请参见 samber/cc-skills-golang@golang-structs-interfaces 技能。

错误流模式

错误情况必须优先处理并提前返回——保持正常路径缩进最小。→ 关于完整模式和示例,请参见 samber/cc-skills-golang@golang-code-style 技能。

何时使用 Panic 与返回错误

  • - 返回错误:网络故障、文件未找到、无效输入——任何调用者可以处理的情况
  • Panic:在不应出现的地方出现 nil 指针、违反不变性、在初始化时使用 Must* 构造函数
  • .Close() 错误:可以不检查——defer f.Close() 无需错误处理即可

数据处理

string vs []byte vs []rune

类型默认用于使用场景
string所有情况不可变、安全、UTF-8
[]byte
I/O | 写入 io.Writer、构建字符串、可变操作 | | []rune | Unicode 操作 | len() 必须表示字符数,而非字节数 |

避免重复转换——每次转换都会分配内存。在需要另一种类型之前,保持使用一种类型。

大型数据的迭代器与流式处理

使用迭代器(Go 1.23+)和流式处理模式来处理大型数据集,无需将所有内容加载到内存中。对于服务之间的大型传输(例如,从数据库到 HTTP 的 100 万行数据),使用流式传输以防止 OOM。

有关代码示例,请参见数据处理模式

资源管理

在打开资源后立即 defer Close()——不要等待,不要忘记:

go
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // 就在这里,而不是 50 行之后

rows, err := db.QueryContext(ctx, query)
if err != nil {
return err
}
defer rows.Close()

关于优雅关闭、资源

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 golang-design-patterns-1776080589 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 golang-design-patterns-1776080589 技能

通过命令行安装

skillhub install golang-design-patterns-1776080589

下载

⬇ 下载 golang-design-patterns v1.1.2(免费)

文件大小: 23.43 KB | 发布时间: 2026-4-14 10:55

v1.1.2 最新 2026-4-14 10:55
- Added `AskUserQuestion` to the list of allowed tools.
- Updated metadata version to 1.1.2.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large
返回顶部