关于 go-functional-options
介绍 Go 函数式选项模式的开发技能,用于配置构造函数和公共 API。帮助开发者判断何时采用选项、如何组织实现,以及何时配置结构体更简单。
主要功能
- 01选择函数式选项的判断依据
- 02Option 接口与内部结构模式
- 03With* 构造函数指导
- 04与配置结构体的比较
- 05测试与文档方面的考量
适用场景
- 01为构造函数配置可选参数
- 02设计可能增加选项的 API
- 03在选项与配置结构体间做选择
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ cxuu/ golang-skills --skill go-functional-options安装后在 Claude Code 中输入/go-functional-options确认已加载。
附带文件references/OPTIONS-VS-STRUCTS.md
详细介绍
函数式选项模式
函数式选项是一种模式:声明一个不透明的 Option 类型,用于在内部结构体中记录信息。构造函数接受可变数量的此类选项,并应用它们来配置结果。
资源路由
references/OPTIONS-VS-STRUCTS.md- 在选择配置结构体还是函数式选项、实现完整的基于接口的选项模式,或评估混合构造函数 API 时阅读。
适用场景
在以下情况下使用函数式选项:
- 构造函数或公共 API 有 3 个或更多可选参数
- 可扩展的 API 可能会随时间增加新选项
- 调用方体验简洁很重要(无需传入默认值)
模式
核心组件
- 未导出的
options结构体 - 保存所有配置 - 导出的
Option接口 - 带有未导出的apply方法 - 选项类型 - 实现该接口
With*构造函数 - 创建选项
Option 接口
type Option interface {
apply(*options)
}
未导出的 apply 方法可确保只有此包中的选项才能使用。
对比:函数式选项与配置结构体
| 方面 | 函数式选项 | 配置结构体 |
|---|---|---|
| 可扩展性 | 添加新的 With* 函数 | 添加新字段(可能造成破坏性变更) |
| 默认值 | 内置于构造函数中 | 使用零值或单独设置默认值 |
| 调用方体验 | 只需指定不同之处 | 必须构造完整的结构体 |
| 可测试性 | 可比较选项 | 比较结构体 |
| 复杂度 | 样板代码更多 | 设置更简单 |
优先选择配置结构体的情况:选项少于 3 个、选项很少变化、通常会同时指定所有选项,或仅用于内部 API。
为什么不使用闭包?
相比仅使用闭包的选项,接口方案更受推荐,原因如下:
- 可测试性 - 可在测试和模拟中比较选项
- 可调试性 - 选项可以实现
fmt.Stringer - 灵活性 - 选项可以实现其他接口
- 可见性 - 选项类型会显示在文档中
快速参考
// 1. Unexported options struct with defaults
type options struct {
field1 Type1
field2 Type2
}
// 2. Exported Option interface, unexported method
type Option interface {
apply(*options)
}
// 3. Option type + apply + With* constructor
type field1Option Type1
func (o field1Option) apply(opts *options) { opts.field1 = Type1(o) }
func WithField1(v Type1) Option { return field1Option(v) }
// 4. Constructor applies options over defaults
func New(required string, opts ...Option) (*Thing, error) {
o := options{field1: defaultField1, field2: defaultField2}
for _, opt := range opts {
opt.apply(&o)
}
// ...
}
检查清单
-
options结构体未导出 -
Option接口具有未导出的apply方法 - 每个选项都有一个
With*构造函数 - 在应用选项前设置默认值
- 必需参数与
...Option分开
相关技能
- 接口设计:设计
Option接口或在接口与闭包方案之间进行选择时,参阅 go-interfaces - 命名约定:为
With*构造函数、选项类型或未导出的 options 结构体命名时,参阅 go-naming - 函数设计:在文件中组织构造函数或格式化可变参数签名时,参阅 go-functions
- 文档:为
Option类型、With*函数或构造函数行为编写文档时,参阅 go-documentation
外部资源
- 自引用函数与选项设计 - Rob Pike
- 用于友好 API 的函数式选项 - Dave Cheney
评论
支持 Markdown