Rego中如何用函数模拟集合生成?多输出错误求解
Rego复用规则的函数实现问题
我希望将一段可复用的Rego规则转换成函数,让多个模块传入参数调用,但遇到了functions must not produce multiple outputs for same inputs错误。以下是简化示例及问题:
可正常运行的常规生成器实现
arr = [1,2,3,4] result[entry] { itm := arr[i] r := itm % 2 r == 0 entry := { "type": "even", "val": itm } } result[entry] { itm := arr[i] r := itm % 2 r == 1 entry := { "type": "odd", "val": itm } }
运行结果
{ "result": [ { "type": "even", "val": 2 }, { "type": "even", "val": 4 }, { "type": "odd", "val": 1 }, { "type": "odd", "val": 3 } ] }
触发错误的函数实现
尝试用函数封装,传入t_label参数(仅作示例),但执行报错:
f(t_label) := q { q := [ entry | itm := arr[i] r := itm % 2 r == 0 entry := { t_label: "even", "val": itm } ] } f(t_label) := q { q := [ entry | itm := arr[i] r := itm % 2 r == 1 entry := { t_label: "odd", "val": itm } ] }
问题解答
这种实现方式不可行的原因
Rego的函数要求确定性:相同输入必须返回唯一输出。你写的两个f(t_label)规则,对同一个t_label参数会生成两个不同数组(一个存偶数项,一个存奇数项),违反了函数的单输出要求,因此触发错误。
Rego中复用这类规则的常规方式
1. 带参数的生成器(推荐)
把规则改成带参数的生成器形式,保留多输出特性的同时支持参数传入:
arr = [1,2,3,4] result(t_label)[entry] { itm := arr[i] r := itm % 2 r == 0 entry := { t_label: "even", "val": itm } } result(t_label)[entry] { itm := arr[i] r := itm % 2 r == 1 entry := { t_label: "odd", "val": itm } }
调用时通过result("type")即可获取所有符合条件的entry集合,和原生成器逻辑一致,同时支持参数复用。
2. 单函数返回合并结果
如果一定要用函数,需把两个分支的结果合并成一个数组返回,确保单输入对应单输出:
arr = [1,2,3,4] f(t_label) := q { evens := [ entry | itm := arr[i] r := itm % 2 r == 0 entry := { t_label: "even", "val": itm } ] odds := [ entry | itm := arr[i] r := itm % 2 r == 1 entry := { t_label: "odd", "val": itm } ] q := concat([], evens + odds) }
这样同一个t_label输入只会返回一个合并后的数组,满足函数的确定性要求。
3. 拆分单职责函数
把偶数和奇数的逻辑拆成两个独立函数,分别处理不同分支,调用时按需使用:
arr = [1,2,3,4] get_evens(t_label) := q { q := [ entry | itm := arr[i] r := itm % 2 r == 0 entry := { t_label: "even", "val": itm } ] } get_odds(t_label) := q { q := [ entry | itm := arr[i] r := itm % 2 r == 1 entry := { t_label: "odd", "val": itm } ] }
这种方式逻辑更清晰,适合分支逻辑差异较大的场景。
内容的提问来源于stack exchange,提问作者Szymon Rozga
相关产品推荐
相关产品推荐

