策略函数签名必须统一,推荐func(ctx context.context, req interface{}) (interface{}, error);map需显式make初始化;key须注册时标准化(如tolower/trim);禁止策略内panic,须返回error。

用 map[string]func() 替代 if-else 链时,函数签名必须一致
策略函数塞进 map 后,调用时没法动态适配不同参数或返回值类型。一旦某个策略需要传 string、另一个要传 int,或者一个返回 error、另一个返回 bool,map 就会立刻报类型不匹配。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有策略函数统一为同一签名,比如
func(ctx context.Context, req interface{}) (interface{}, error),靠运行时类型断言或结构体字段区分行为 - 避免用
map[string]interface{}存策略——看似灵活,实际调用前得反复类型断言,出错难定位 - 如果策略间输入差异大,宁可拆成多个
map,比如map[string]func(string) error和map[string]func(int) bool,别硬塞进一个泛型容器
注册策略时忘记初始化 map 导致 panic: assignment to entry in nil map
直接声明 var strategies map[string]func() 而不 make,后续往里塞函数就会触发 panic。这个错误在单元测试里容易漏掉,因为局部变量没被调用就过了,但上线后一执行策略路由就崩。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 策略
map必须显式make,推荐在包级变量初始化时完成:var strategies = make(map[string]func(), 8) - 如果策略需动态加载(如插件化),把
make放到初始化函数里,并加注释说明“此 map 不可为 nil” - 用
sync.Map替代普通map?没必要——策略注册通常只在启动期发生,且是单次写入,sync.Map的读性能优势在此场景毫无意义,反而增加理解成本
策略名大小写/空格/特殊字符不规范,导致 runtime lookup 失败
用户输入的策略标识符(比如 HTTP header 里的 X-Strategy)和 map key 对不上,常见于前端传 "pay_alipay",而代码里注册的是 "PayAlipay" 或 "pay_alipay "(末尾空格)。结果 strategies[strategyName] 返回零值函数,一调就 panic。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 注册策略时统一用
strings.ToLower规范 key:strategies[strings.ToLower(name)] = fn - lookup 前先 trim 空格:
strategies[strings.TrimSpace(input)],别指望上游永远干净 - 加一层兜底日志:
if fn == nil { log.Printf("unknown strategy: %q", input) },比静默失败好调试得多
策略函数里直接 panic 而非返回 error,破坏调用方错误处理逻辑
策略本该是可预期的业务分支,但有人在策略函数里写 panic("not implemented") 或 panic(err),导致上层无法用 if err != nil 统一处理,只能靠 recover 拦截——这违背了 Go 的错误处理约定,也掩盖了真实问题位置。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 策略函数签名强制包含
error返回值,任何异常路径都走return nil, errors.New(...) - 禁止在策略函数内使用
panic,CI 可加静态检查(如golint+ 自定义规则)拦截panic(调用 - 若真遇到不可恢复错误(如配置严重缺失),应提前在校验阶段暴露,而不是等到策略执行时才 panic










