后端与接口
设计 Go 构造函数时用函数式选项处理多个可选参数
当 Go 构造函数或工厂函数有 3 个以上可选配置项、或 API 需要可扩展时,用函数式选项模式替代配置结构体。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
设计 Go 构造函数时用函数式选项处理多通用
解决思路
- 声明一个不导出的 `options` 结构体,保存所有配置字段,并在构造函数中先填入默认值。
- 声明一个导出的 `Option` 接口,包含一个不导出的 `apply(*options)` 方法,确保只有本包能实现该接口。
- 为每个可选项定义一个选项类型(如 `type field1Option Type1`),实现 `apply` 方法把值写入 `options` 结构体。
- 为每个选项提供 `With*` 构造函数(如 `func WithField1(v Type1) Option`),返回对应的选项类型。
- 构造函数签名采用 `func New(required string, opts ...Option) (*Thing, error)`,必填参数与 `...Option` 分开。
- 在构造函数中先创建带默认值的 `options` 实例,再遍历 `opts` 依次调用 `opt.apply(&o)` 覆盖默认值。
- 优先使用接口式选项而非纯闭包式选项,以便选项可比较、可实现 `fmt.Stringer`、可扩展其他接口并在文档中可见。
- 当可选参数少于 3 个、选项很少变化、通常一次性全部指定、或仅用于内部 API 时,改用配置结构体。
- 按检查清单核对:`options` 结构体不导出、`Option` 接口方法不导出、每个选项都有 `With*` 构造函数、默认值在应用选项前设置、必填参数独立于 `...Option`。
- 需要选择配置结构体还是函数式选项、实现完整的基于接口的选项模式或评估混合构造函数 API 时,阅读 `references/OPTIONS-VS-STRUCTS.md`。
适用边界 · 注意事项
- 可选参数少于 3 个,或选项很少变化、通常一次性全部指定时,用配置结构体更简单。
- 仅用于内部 API、不需要对外保持可扩展性时,函数式选项的额外样板代码不划算。
- 不属于构造函数或工厂函数的一般函数设计问题,应参考 go-functions 而非本模式。