BLOGE
0.9.8-RC1在线版 · 事实校验 2026-09-15 · English
附录 A —— 内置函数
bloge DSL 中所有的 guard、constraint 与表达式共享同一组内置函数。本附录是这套工 具箱的唯一参考:每个函数名、每个签名、每个陷阱都在这里。当你开始写真实的 DSL, 就把它收藏起来。
什么时候需要这份参考
| 问题 | 章节 |
|---|---|
coalesce / ifNull / isNull 各自做什么? | 第 5 节:Null 与默认值 |
when: 守卫里能用正则吗? | 第 1 节:字符串函数 |
| 怎么对列表字段求和或求平均? | 第 2 节:数学与聚合 |
| 怎么读嵌套 map 里的值? | 第 4 节:Map 与对象 |
| 怎么格式化时间戳或计算时长? | 第 7 节:日期/时间 |
| 怎么签名或哈希一段载荷? | 可选模块:bloge-functions-crypto |
| 怎么判断某个函数能否在编译期使用? | 纯函数与编译期求值 |
按任务查函数
| 我要做什么 | 先查哪里 |
|---|---|
| 清洗、拆分、匹配或格式化文本 | 字符串函数 |
| 汇总、比较、取整或聚合数值 | 数学与聚合 |
| 过滤、映射、展平或检查列表 | 集合函数 |
| 安全读取嵌套对象或 map | Map/对象与 null 处理 |
| 在 schema 校验前转换类型 | 类型转换 |
| 计算 deadline 或 duration | 日期/时间函数 |
| 创建摘要或签名 | 可选 crypto 模块 |
第 5 章 (会分支的图) 在 when: guard 里引入了这些函数。第 7 章 (设计良好的算子) 在
算子的 constraints 与 usageExample 中使用它们。第 15 章 (状态机) 在转换 guard
中使用它们。在 bloge DSL 中只要见到表达式,能调用的就是本附录列出的这套函数。
函数调用语法
所有函数都使用标准调用语法:
when: concat("Hello, ", ctx.name) == "Hello, Alice"
when: contains(split(ctx.tags, ","), "premium")
when: padLeft(toString(ctx.id), 10, "0")
bloge 没有 Unix 风格的管道操作符 (|)。| 在词法分析中保留给逻辑或 (||)。
要组合多个函数,就把调用嵌套起来。
Null 处理约定
核心内置函数默认 null 安全。传 null 时要么:
- 返回
null(safe-nav 语义);要么 - 返回一个合理的默认值 ——
size(null) → 0、isEmpty(null) → true、concat(null, "x") → "x"等等。
你可以依赖这个约定,少写很多防御性判断。可选的加密模块是唯一的例外,参见下文。
纯函数与编译期求值
绝大多数函数是纯函数 —— 相同输入总是产生相同输出,没有副作用。当参数是常量 时,DSL 编译器允许在编译期折叠这些纯函数调用。
少数函数是非纯函数,不可折叠:
now()—— 当前时间戳,来自引擎的 time sourcetoday()—— 当前日期,来自引擎的 time sourceuuid()—— 随机 UUIDsecret(name)—— 密钥查询 (加密模块)
在严格的"编译期专属"位置 (常量、schema constraint),编译器会拒绝非纯函数调用。把 它们留到运行期的 guard 里使用。
1. 字符串函数 (17)
| 函数 | 签名 | 返回 | 说明 |
|---|---|---|---|
concat | concat(arg1, arg2, …) | String | 把所有参数按字符串拼接。null 视为空串。 |
substring | substring(str, start [, end]) | String | 从 start (含) 到 end (不含);自动钳制越界。 |
uppercase / upper | uppercase(str) | String | 转大写。 |
lowercase / lower | lowercase(str) | String | 转小写。 |
trim | trim(str) | String | 去掉首尾空白。 |
replace | replace(str, oldStr, newStr) | String | 把所有字面量 oldStr 替换为 newStr。 |
startsWith | startsWith(str, prefix) | Boolean | 前缀判断;遇 null 返回 false。 |
endsWith | endsWith(str, suffix) | Boolean | 后缀判断;遇 null 返回 false。 |
indexOf | indexOf(str, target) | Number | 第一次出现的下标,找不到返回 -1。 |
length / len | length(str) | Number | 字符串长度;列表、map 同样适用;null 返回 0。 |
matches | matches(str, regex) | Boolean | 正则匹配;null 或正则错误返回 false (不抛异常)。 |
replaceAll | replaceAll(str, regex, replacement) | String | 正则全量替换;null 或正则错误返回原值。 |
split | split(str, delimiter) | List | 按字面分隔符 (非正则) 切分;null 返回空列表。 |
join | join(list, delimiter) | String | 用分隔符拼接列表元素;null 元素变空串。 |
padLeft | padLeft(str, length, padChar) | String | 用单字符左填充到指定长度。 |
padRight | padRight(str, length, padChar) | String | 用单字符右填充到指定长度。 |
when: startsWith(ctx.email, "admin@") and contains(ctx.email, "@")
when: matches(ctx.phone, "^\\+?[0-9 ]{6,}$")
when: padLeft(toString(ctx.orderId), 8, "0") == "00012345"
2. 数学与聚合 (10)
| 函数 | 签名 | 返回 | 说明 |
|---|---|---|---|
abs | abs(n) | Number | 绝对值。 |
min | min(a, b) | Number | 两数最小值。 |
max | max(a, b) | Number | 两数最大值。 |
round | round(n) | Number | 四舍五入到整数 (Math.round)。 |
ceil | ceil(n) | Number | 向上取整。 |
floor | floor(n) | Number | 向下取整。 |
clamp | clamp(n, min, max) | Number | 把 n 钳到 [min, max]。 |
pow | pow(base, exponent) | Number | base ^ exponent。 |
sum | sum(list) | Number | 数值元素求和;null 跳过;空列表返回 0。 |
avg | avg(list) | Number | 数值元素求平均;空或 null 返回 null。 |
when: sum(ctx.items.*.price) > 1000
when: clamp(ctx.retries, 0, 5) == ctx.retries
3. 集合函数 (13)
| 函数 | 签名 | 返回 | 说明 |
|---|---|---|---|
size | size(collection) | Number | 列表 / map / 字符串的长度;null 返回 0。 |
contains | contains(collection, item) | Boolean | 成员判断。列表→精确匹配;字符串→子串;map→是否含该键。 |
first | first(list) | any | 第一个元素;空或 null 返回 null。 |
last | last(list) | any | 最后一个元素;空或 null 返回 null。 |
isEmpty | isEmpty(collection) | Boolean | 空或 null 返回 true。 |
distinct | distinct(list) | List | 去重并保持原顺序。 |
flatten | flatten(listOfLists) | List | 展平一层;非列表元素透传。 |
sort | sort(list) | List | 自然序排序,落到 toString 作为后备;null 排在前面。 |
take | take(list, n) | List | 前 n 个元素。 |
drop | drop(list, n) | List | 跳过前 n 个元素。 |
reverse | reverse(list) | List | 反转顺序。 |
any | any(list, value) | Boolean | 是否存在等于 value 的元素。 |
all | all(list, value) | Boolean | 是否所有元素都等于 value;空列表返回 true。 |
when: contains(ctx.tags, "premium") and size(ctx.items) > 0
when: any(ctx.errors, "TIMEOUT")
when: all(distinct(ctx.statuses), "OK")
4. Map 与对象 (5)
| 函数 | 签名 | 返回 | 说明 |
|---|---|---|---|
keys | keys(map) | List | 所有键作为列表返回。 |
values | values(map) | List | 所有值作为列表返回。 |
entries | entries(map) | List | 返回 {key, value} map 列表。 |
merge | merge(map1, map2) | Map | 浅合并;map2 覆盖 map1。 |
has | has(map, key) | Boolean | map 是否含该键。 |
when: has(ctx.headers, "X-Trace-Id")
when: size(keys(ctx.attributes)) > 3
5. Null 与默认值 (3)
| 函数 | 签名 | 返回 | 说明 |
|---|---|---|---|
coalesce | coalesce(v1, v2, …) | any | 第一个非 null 的参数;全都是 null 则返回 null。 |
isNull | isNull(value) | Boolean | 是否为 null。 |
isNotNull | isNotNull(value) | Boolean | 是否非 null。 |
coalesce 是默认值的主力。如果只需要一个回退值,第 9 节“高级工具”中的
ifNull 读起来更自然。
when: isNotNull(ctx.userId)
let region = coalesce(ctx.region, ctx.country, "GLOBAL")