90%的条件判断类规则用govaluate足够,它轻量稳定、适合风控白名单等场景,但需严格匹配字段名大小写、预检变量、缓存表达式实例、注册时间函数而非静态值,且不支持复杂流程编排。

直接用 if/else 硬编码处理超过 5 条、且需月均调整 3 次以上的业务规则,不出三个月就会卡在发布前的回归测试上——这不是开发能力问题,是结构缺陷。
govaluate 足够应付 90% 的条件判断类规则
它不是“规则引擎”全家桶,但对风控白名单、优惠券发放门槛、工单自动分派这类「表达式为主、动作极少」的场景,govaluate 是最轻、最稳、最容易 debug 的选择。
- 表达式字符串必须严格匹配变量字段名大小写,
user.City和user.city是两个世界 - 所有被引用的 key 必须出现在传入的
map[string]interface{}中,哪怕值为nil;否则直接panic: interface conversion: interface {} is nil - 高频调用务必缓存
govaluate.EvaluableExpression实例,别每次govaluate.NewEvaluableExpression(expr) - 时间类逻辑(如“7天内”)不能靠初始化时注入
now := time.Now(),得注册函数:vars["now"] = func() time.Time { return time.Now() }
Gengine 适合需要优先级调度和热更新的复杂流程
当规则之间存在强依赖(比如“先验资,再授信,最后放款”),或运营人员要随时改规则不重启服务,Gengine 的 AST 解析 + 多执行模式才是正解。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
-
SortModel按salience降序执行,但不会跳过低优规则——想“命中即停”,得在then块里手动设Stop标志并配合ExecuteWithStopTagDirect - 规则文件是纯文本(.grl),但变量绑定只认 struct 字段或 map key,不支持
user.Profile.Address.Street这种深层链式访问,会 panic - 并发模式(
ConcurrentModel)下,各规则 goroutine 共享同一个KnowledgeContext,写操作必须加锁,否则数据竞争 - 热更新不是“替换文件就生效”,得调用
ruleBuilder.BuildRuleFromBytes()+gengine.Reset(),漏掉任一环节规则就不会刷新
grule 在 DSL 可读性和热重载之间折中可行
如果你的规则要给产品/运营直接看、改,又不想引入 JS/Lua 这类外部运行时,grule 的类 Drools DSL 是目前 Go 生态里最平衡的选择。
-
salience控制顺序,但它只是提示,不是硬约束;两条规则条件都满足时,仍可能并发触发——靠when里的排他条件(如$user.Role != "vip")兜底 - 规则中调用方法仅限一级,
$user.GetOrders()可以,$user.GetOrders().Filter()会报unknown function - 热重载需监听文件变化 + 调用
knowledgebase.LoadRulesFromBytes(),但旧规则实例不会自动销毁,得自己管理生命周期 - 不支持跨规则共享状态,想做“累计满 3 次下单送礼”,得把计数器塞进传入的
dataContext并手动维护
真正容易被忽略的是:没有银弹。选 govaluate 就得接受它只管“判”,不管“做”;选 Gengine 就得亲手处理 goroutine 安全和上下文污染;选 grule 就得默认承担 DSL 学习成本和 salience 语义模糊带来的调试开销。规则越靠近业务核心,越要提前约定好谁负责校验、谁负责兜底、谁来监控执行失败。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










