通用表达式语言 (CEL) API 参考文档

本文档是通用表达式语言 (CEL) 的统一 API 文档参考。其中列出了所有宏、运算符和标准函数,并指明了它们在官方 CEL 堆栈中的签名、行为和支持状态。

如需详细了解语言行为和规范,请参阅 CEL 语言定义

堆叠版本

本参考文档基于以下版本的 CEL 堆栈:

  • CEL Gov0.29.2(及更高版本)
  • CEL C++v0.15.0
  • CEL Javav0.13.1
  • CEL Pythonv0.1.3
  • CEL C:开发版快照(未发布)

GitHub 镜像

CEL 的官方实现镜像在 GitHub 上的 cel-expr 组织下:


1. 核心宏

这些是内置宏,会在编译时展开。

说明 Go C++ Java Python C
has(container.field) 测试字段是否存在于消息中,或键是否存在于映射中。

签名
has(container.field) -> bool

示例
has(request.auth.claims.email)
list.all(var, predicate) 测试列表中的所有元素是否都满足某个谓词。

签名
list.all(var, predicate) -> bool

示例
[1, 2, 3].all(x, x > 0) // true
¹
list.exists(var, predicate) 测试列表中是否至少有一个元素满足谓词。

签名
list.exists(var, predicate) -> bool

示例
[1, 2, 3].exists(x, x > 2) // true
¹
list.exists_one(var, predicate) 测试列表中是否恰好有一个元素满足谓词。

签名
list.exists_one(var, predicate) -> bool

示例
[1, 2, 3].exists_one(x, x == 2) // true
¹
list.filter(var, predicate) 根据谓词过滤列表的元素。

签名
list.filter(var, predicate) -> list

示例
[1, 2, 3].filter(x, x > 1) // [2, 3]
¹
list.map(var, transform) 使用表达式转换列表的每个元素。

签名
list.map(var, transform) -> list

示例
[1, 2, 3].map(x, x * 2) // [2, 4, 6]
¹
list.map(var, filter, transform) 转换满足过滤谓词的列表元素。

签名
list.map(var, filter, transform) -> list

示例
[1, 2, 3].map(x, x > 1, x * 2) // [4, 6]
¹

¹ 在 C 运行时中受支持,因为宏在编译期间由宿主编译器扩展为推导式。


2. 核心运算符

运算符 说明 Go C++ Java Python C
算术(+-*/% 标准算术运算。取反 (-x) 和恒等 (+x)。Go、C++、Java 和 Python 支持列表串联 (list + list)。

签名
T + T -> T
T - T -> T
T * T -> T
T / T -> T
T % T -> T
-T -> T
+T -> T
list + list -> list

示例
1 + 2 * 3 // 7
[1] + [2] // [1, 2]
²
比较(==!=<<=>>= 标准比较。数值比较是异构的(例如 1 == 1.0)。

签名
T == T -> bool
T != T -> bool
T < T -> bool
T <= T -> bool
T > T -> bool
T >= T -> bool

示例
x < 42.0
1 == 1.0 // true
逻辑(!&&||? : 逻辑 NOT、AND、OR 和三元条件。和/或使用短路求值。

签名
!bool -> bool
bool && bool -> bool
bool || bool -> bool
bool ? T : T -> T

示例
x > 0 ? "positive" : "non-positive"
编入索引 ([]) 按索引访问列表的元素,或按键查找映射中的键。

签名
list[int] -> T
map[K] -> V

示例
tags[0]
users['john']
会员资格 (in) 检查元素是否在列表中,或键是否在映射中。

签名
T in list -> bool
K in map -> bool

示例
'admin' in roles

² C 运行时不支持列表串联 (list + list),但支持其他算术运算符。


3. 核心功能

常规函数和字符串函数

函数 说明 Go C++ Java Python C
size 返回字符串(字符)、字节、列表或映射的大小。

签名
size(T) -> int(其中 Tstringbyteslistmap<br /><br />**Examples:**<br />size("hello") // 5`
contains 返回字符串是否包含子字符串。

签名
string.contains(string) -> bool

示例
"hello".contains("ell") // true
startsWith 返回字符串是否以指定前缀开头。

签名
string.startsWith(string) -> bool

示例
"hello".startsWith("he") // true
endsWith 返回字符串是否以后缀结尾。

签名
string.endsWith(string) -> bool

示例
"hello".endsWith("lo") // true
matches 返回字符串是否与 RE2 正则表达式匹配。

签名
string.matches(string) -> bool

示例
"123".matches(r"^\d+$") // true

日期和时间选择器函数

这些函数从 google.protobuf.Timestampgoogle.protobuf.Duration 中提取组件。

函数 说明 Go C++ Java Python C
getFullYear 返回 4 位数的年份。

签名
timestamp.getFullYear([tz]) -> int

示例
timestamp("2026-07-23T00:00:00Z").getFullYear() // 2026
getMonth 返回月份(0-11)。

签名
timestamp.getMonth([tz]) -> int

示例
timestamp("2026-07-23T00:00:00Z").getMonth() // 6
getDayOfMonth 返回日期(1-31)。

签名
timestamp.getDayOfMonth([tz]) -> int

示例
timestamp("2026-07-23T00:00:00Z").getDayOfMonth() // 23
getDayOfWeek 返回星期几(0 表示星期日)。

签名
timestamp.getDayOfWeek([tz]) -> int

示例
timestamp("2026-07-23T00:00:00Z").getDayOfWeek() // 4
getDayOfYear 返回一年中的第几天(0-365)。

签名
timestamp.getDayOfYear([tz]) -> int

示例
timestamp("2026-07-23T00:00:00Z").getDayOfYear() // 203
getHours 返回小时数(0-23)。

签名
timestamp.getHours([tz]) -> int
duration.getHours() -> int

示例
duration("1h30m").getHours() // 1
getMinutes 返回分钟数(0-59)。

签名
timestamp.getMinutes([tz]) -> int
duration.getMinutes() -> int

示例
duration("1h30m").getMinutes() // 30
getSeconds 返回秒数(0-59)。

签名
timestamp.getSeconds([tz]) -> int
duration.getSeconds() -> int

示例
duration("1h30m45s").getSeconds() // 45
getMilliseconds 返回毫秒数(0-999)。

签名
timestamp.getMilliseconds([tz]) -> int
duration.getMilliseconds() -> int

示例
duration("1.5s").getMilliseconds() // 500

类型转换

目标类型 说明 Go C++ Java Python C
bool 转换为布尔值。

签名
bool(bool) -> bool
bool(string) -> bool

示例
bool("true") // true
bytes 转换为字节。

签名
bytes(bytes) -> bytes
bytes(string) -> bytes

示例
bytes("hello") // b"hello"
double 转换为双精度浮点数。

签名
double(double) -> double
double(int) -> double
double(uint) -> double
double(string) -> double

示例
double(1) // 1.0
duration 转换为时长。

签名
duration(duration) -> duration
duration(string) -> duration

示例
duration("1.5s") // 1.5s duration
int 转换为 64 位有符号整数。

签名
int(int) -> int
int(uint) -> int
int(double) -> int(四舍五入到零)
int(string) -> int
int(timestamp) -> int(自纪元以来的秒数)

示例
int(1.5) // 1
string 转换为字符串。

签名
string(T) -> string(支持 boolintuintdoublebytestimestampduration<br /><br />**Examples:**<br />string(1.5) // "1.5"`
timestamp 转换为时间戳。

签名
timestamp(timestamp) -> timestamp
timestamp(string) -> timestamp (RFC3339)

示例
timestamp("2026-07-23T00:00:00Z")
uint 转换为 64 位无符号整数。

签名
uint(uint) -> uint
uint(int) -> uint
uint(double) -> uint
uint(string) -> uint

示例
uint(1) // 1u
dyn 将值强制转换为动态类型以进行类型检查。

签名
dyn(T) -> dyn

示例
dyn([1, "two"])
type 返回值的类型。

签名
type(T) -> type

示例
type(1) // int

4. 扩展程序(库)

绑定库

函数 说明 Go C++ Java Python C
cel.bind 绑定局部变量以避免重复评估。

签名
cel.bind(varName, initExpr, resultExpr) -> T

示例
cel.bind(x, a + b, x * x)
(v0.15.0) (v0.10.0) (v0.2.0) (v0.1.1)

如何启用

编码器库

函数 说明 Go C++ Java Python C
base64.encode 将字节编码为 base64 字符串。

签名
base64.encode(bytes) -> string

示例
base64.encode(b"hello") // "aGVsbG8="
(v0.6.0) (v0.10.0) (v0.2.0) (v0.1.1)
base64.decode 将 base64 字符串解码为字节。在输入无效时抛出错误。

签名
base64.decode(string) -> bytes

示例
base64.decode("aGVsbG8=") // b"hello"
(v0.6.0) (v0.10.0) (v0.2.0) (v0.1.1)
json.encode 将 CEL 值序列化为 JSON 字符串。

签名
json.encode(dyn) -> string

示例
json.encode([1, 2]) // "[1,2]"
(v0.29.0)

如何启用

数学库

函数 说明 Go C++ Java Python C
math.greatest 返回数值实参(或数值列表)中的最大值。

签名
math.greatest(arg, ...) -> T

示例
math.greatest(1, 3, 2) // 3
(v0.13.0) (v0.10.0) (v0.2.0) (v0.1.1)
math.least 返回数值实参(或数值列表)中的最小值。

签名
math.least(arg, ...) -> T

示例
math.least([1, 3, 2]) // 1
(v0.13.0) (v0.10.0) (v0.2.0) (v0.1.1)
math.abs 绝对值。

签名
math.abs(T) -> T(支持 intuintdouble<br /><br />**Examples:**<br />math.abs(-1) // 1`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.sqrt 平方根。

签名
math.sqrt(T) -> double(支持 intuintdouble<br /><br />**Examples:**<br />math.sqrt(9) // 3.0`
(v0.25.1) (v0.12.0) (v0.11.0) (v0.1.1)
math.bitAnd 按位 AND。

签名
math.bitAnd(T, T) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitAnd(5, 3) // 1`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.bitOr 按位 OR。

签名
math.bitOr(T, T) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitOr(5, 3) // 7`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.bitXor 按位异或。

签名
math.bitXor(T, T) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitXor(5, 3) // 6`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.bitNot 按位 NOT。

签名
math.bitNot(T) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitNot(1) // -2`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.bitShiftLeft 按位左移。

签名
math.bitShiftLeft(T, int) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitShiftLeft(1, 2) // 4`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.bitShiftRight 按位右移。

签名
math.bitShiftRight(T, int) -> T(支持 intuint<br /><br />**Examples:**<br />math.bitShiftRight(4, 2) // 1`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.ceil 向上舍入。

签名
math.ceil(double) -> double

示例
math.ceil(1.2) // 2.0
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.floor 向下舍入。

签名
math.floor(double) -> double

示例
math.floor(1.8) // 1.0
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.round 舍入到最接近的整数。

签名
math.round(double) -> double

示例
math.round(1.5) // 2.0
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.trunc 截断舍入(向零靠拢)。

签名
math.trunc(double) -> double

示例
math.trunc(-1.8) // -1.0
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.isInf 检查 double 是否为正无穷大或负无穷大。

签名
math.isInf(double) -> bool

示例
math.isInf(1.0/0.0) // true
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.isNaN 检查 double 是否为 NaN。

签名
math.isNaN(double) -> bool

示例
math.isNaN(0.0/0.0) // true
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.isFinite 检查 double 是否为有限值。

签名
math.isFinite(double) -> bool

示例
math.isFinite(1.2) // true
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)
math.sign 返回值的符号(-1、0 或 1)。

签名
math.sign(T) -> T(支持 intuintdouble<br /><br />**Examples:**<br />math.sign(-42) // -1`
(v0.21.0) (v0.11.0) (v0.10.1) (v0.1.1)

如何启用

Protos 库

函数 说明 Go C++ Java Python C
proto.getExt 获取 proto2 扩展字段,如果未设置,则获取默认值。

签名
proto.getExt(msg, extName) -> T

示例
proto.getExt(msg, google.api.expr.test.int32_ext)
(v0.13.0) (v0.10.0) (v0.2.0) (v0.1.1)
proto.hasExt 检查是否设置了 proto2 扩展字段。

签名
proto.hasExt(msg, extName) -> bool

示例
proto.hasExt(msg, google.api.expr.test.int32_ext)
(v0.13.0) (v0.10.0) (v0.2.0) (v0.1.1)

如何启用

列出媒体库

函数 说明 Go C++ Java Python C
distinct 返回不同的元素。

签名
list.distinct() -> list

示例
[1, 2, 2].distinct() // [1, 2]
(v0.22.0) (v0.11.0) (v0.11.0) (v0.1.1)
flatten 展平嵌套列表。

签名
list.flatten([depth]) -> list

示例
[[1], [2, 3]].flatten() // [1, 2, 3]
(v0.22.0) (v0.11.0) (v0.7.1) (v0.1.1)
lists.range 返回整数列表 [0, ..., n-1]

签名
lists.range(int) -> list(int)

示例
lists.range(3) // [0, 1, 2]
(v0.22.0) (v0.11.0) (v0.10.1) (v0.1.1)
reverse 反转列表。

签名
list.reverse() -> list

示例
[1, 2].reverse() // [2, 1]
(v0.22.0) (v0.11.0) (v0.11.0) (v0.1.1)
slice 返回子列表(包含起始值,但不含结束值)。

签名
list.slice(start, end) -> list

示例
[1, 2, 3].slice(1, 3) // [2, 3]
(v0.17.0) (v0.11.0) (v0.11.0) (v0.1.1)
sort 对可比较元素的列表进行排序。

签名
list.sort() -> list

示例
[3, 1, 2].sort() // [1, 2, 3]
(v0.22.0) (v0.11.0) (v0.11.0) (v0.1.1)
sortBy 按根据表达式评估的键对列表进行排序。

签名
list.sortBy(var, expr) -> list

示例
[{"val": 2}, {"val": 1}].sortBy(x, x.val) // [{"val": 1}, {"val": 2}]
(v0.22.0) (v0.11.0) (v0.11.0) (v0.1.1)
first 以可选形式返回第一个元素。需要使用可选扩展服务。

签名
list.first() -> optional

示例
[1, 2].first() // optional(1)
(v0.23.0) (v0.15.0) (v0.11.0) (v0.1.2)
last 以可选形式返回最后一个元素。需要使用可选扩展服务。

签名
list.last() -> optional

示例
[1, 2].last() // optional(2)
(v0.23.0) (v0.15.0) (v0.11.0) (v0.1.2)

如何启用

套装库

函数 说明 Go C++ Java Python C
sets.contains 检查 list1 是否包含 list2 的所有元素。

签名
sets.contains(list1, list2) -> bool

示例
sets.contains([1, 2], [1]) // true
(v0.15.0) (v0.10.0) (v0.6.0) (v0.1.1)
sets.equivalent 检查列表是否在集合上等效(包含相同的唯一元素)。

签名
sets.equivalent(list1, list2) -> bool

示例
sets.equivalent([1, 2], [2, 1, 1]) // true
(v0.15.0) (v0.10.0) (v0.6.0) (v0.1.1)
sets.intersects 检查列表是否共用至少一个元素。

签名
sets.intersects(list1, list2) -> bool

示例
sets.intersects([1, 2], [2, 3]) // true
(v0.15.0) (v0.10.0) (v0.6.0) (v0.1.1)

如何启用

字符串库

函数 说明 Go C++ Java Python C
charAt 返回指定索引处的字符。

签名
string.charAt(int) -> string

示例
"hello".charAt(1) // "e"
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
indexOf 返回子字符串首次出现的索引,如果未找到,则返回 -1。

签名
string.indexOf(substr, [start]) -> int

示例
"hello".indexOf("l") // 2
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
lastIndexOf 返回子字符串最后一次出现的索引,如果未找到,则返回 -1。

签名
string.lastIndexOf(substr, [end]) -> int

示例
"hello".lastIndexOf("l") // 3
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
join 串联字符串。

签名
list(string).join([separator]) -> string

示例
["a", "b"].join("-") // "a-b"
(v0.10.0) (v0.10.0) (v0.2.0) (v0.1.1)
split 按分隔符拆分字符串。

签名
string.split(separator, [limit]) -> list(string)

示例
"a-b".split("-") // ["a", "b"]
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
substring 返回子字符串(含起始索引,不含结束索引)。

签名
string.substring(start, [end]) -> string

示例
"hello".substring(1, 3) // "el"
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
trim 去除 Unicode 空白字符。

签名
string.trim() -> string

示例
" hello ".trim() // "hello"
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
replace 将旧值替换为新值。

签名
string.replace(old, new, [limit]) -> string

示例
"hello".replace("l", "w") // "hewwo"
(v0.4.0) (v0.10.0) (v0.2.0) (v0.1.1)
reverse 反转 Unicode 码位。

签名
string.reverse() -> string

示例
"abc".reverse() // "cba"
(v0.18.0) (v0.14.0) (v0.13.0) (v0.1.1)
lowerAscii 将 ASCII 字符转换为小写。

签名
string.lowerAscii() -> string

示例
"Hello".lowerAscii() // "hello"
(v0.6.0) (v0.11.0) (v0.2.0) (v0.1.1)
upperAscii 将 ASCII 字符转换为大写。

签名
string.upperAscii() -> string

示例
"Hello".upperAscii() // "HELLO"
(v0.6.0) (v0.11.0) (v0.2.0) (v0.1.1)
quote 转义字符串以进行安全打印。

签名
strings.quote(string) -> string

示例
strings.quote("a\tb") // "\"a\\tb\""
(v0.14.0) (v0.14.0) (v0.13.0) (v0.1.1)

如何启用

正则表达式库

函数 说明 Go C++ Java Python C
regex.replace 使用替换字符串替换匹配项(支持反向引用)。

签名
regex.replace(target, pat, repl, [limit]) -> string

示例
regex.replace("123-456", r"(\d+)-(\d+)", r"\2-\1") // "456-123"
(v0.25.1) (v0.13.0) (v0.10.1) (v0.1.1)
regex.extract 返回模式的第一个匹配项(必须有一个捕获组)。

签名
regex.extract(target, pat) -> optional(string)

示例
regex.extract("a123b", r"(\d+)") // optional("123")
(v0.25.1) (v0.13.0) (v0.10.1) (v0.1.1)
regex.extractAll 返回模式的所有匹配项(必须有一个捕获组)。

签名
regex.extractAll(target, pat) -> list(string)

示例
regex.extractAll("a1b2", r"(\d+)") // ["1", "2"]
(v0.25.1) (v0.13.0) (v0.10.1) (v0.1.1)

如何启用

双变量推导式

说明 Go C++ Java Python C
all 对键/索引和值进行短路逻辑 AND 运算。

签名
list.all(i, v, pred) -> bool
map.all(k, v, pred) -> bool

示例
[1, 2].all(i, v, v > 0) // true
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)
exists 对键/索引和值进行短路逻辑或运算。

签名
list.exists(i, v, pred) -> bool
map.exists(k, v, pred) -> bool

示例
[1, 2].exists(i, v, v == 2) // true
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)
existsOne 检查是否恰好有一对满足谓词。

签名
list.existsOne(i, v, pred) -> bool
map.existsOne(k, v, pred) -> bool

示例
[1, 2].existsOne(i, v, v == 2) // true
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)
transformList 将列表/映射转换为列表。

签名
list.transformList(i, v, [filter], transform) -> list
map.transformList(k, v, [filter], transform) -> list

示例
[1, 2].transformList(i, v, v * 2) // [2, 4]
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)
transformMap 将列表/映射的值转换为映射(键保持不变)。

签名
list.transformMap(i, v, [filter], transform) -> map
map.transformMap(k, v, [filter], transform) -> map

示例
[1, 2].transformMap(i, v, v * 2) // {0: 2, 1: 4}
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)
transformMapEntry 转换为地图。

签名
list.transformMapEntry(i, v, [filter], transform_entry) -> map
map.transformMapEntry(k, v, [filter], transform_entry) -> map

示例
[1, 2].transformMapEntry(i, v, {string(v): v * 2}) // {"1": 2, "2": 4}
(v0.22.0) (v0.14.0) (v0.11.0) (v0.1.1)

如何启用

原生类型库

功能 说明 Go C++ Java Python C
原生结构体 在 CEL 中注册和实例化宿主原生类型(Go 结构体 / Java POJO)。

示例
Account{id: 123}(在 CEL 中实例化的 Java POJO)
(v0.13.0) (v0.13.0)

如何启用

网络库

网络库提供用于解析、验证和操作 IP 地址和 CIDR 块的函数。

函数 说明 Go C++ Java Python C
ip 将字符串解析为 IP 地址,或从 CIDR 中提取 IP。

签名
ip(string) -> IP
CIDR.ip() -> IP

示例
ip("192.168.0.1")
cidr("192.168.0.0/24").ip()
(v0.29.0)
isIP 检查字符串是否为有效的 IP 地址。

签名
isIP(string) -> bool

示例
isIP("192.168.0.1") // true
(v0.29.0)
ip.isCanonical 检查 IP 地址字符串是否采用规范格式。

签名
ip.isCanonical(string) -> bool

示例
ip.isCanonical("192.168.0.1") // true
(v0.29.0)
cidr 将字符串解析为 CIDR 块。

签名
cidr(string) -> CIDR

示例
cidr("192.168.0.0/24")
(v0.29.0)
isCIDR 检查字符串是否为有效的 CIDR 地址块。

签名
isCIDR(string) -> bool

示例
isCIDR("192.168.0.0/24") // true
(v0.29.0)
containsIP 检查 CIDR 块是否包含 IP 地址。

签名
CIDR.containsIP(IP) -> bool
CIDR.containsIP(string) -> bool

示例
cidr("192.168.0.0/24").containsIP(ip("192.168.0.1")) // true
(v0.29.0)
containsCIDR 检查一个 CIDR 块是否包含另一个 CIDR 块。

签名
CIDR.containsCIDR(CIDR) -> bool
CIDR.containsCIDR(string) -> bool

示例
cidr("192.168.0.0/16").containsCIDR(cidr("192.168.1.0/24")) // true
(v0.29.0)
family 返回 IP 系列(4 表示 IPv4,6 表示 IPv6)。

签名
IP.family() -> int

示例
ip("192.168.0.1").family() // 4
(v0.29.0)
isGlobalUnicast 检查 IP 是否为全球单播地址。

签名
IP.isGlobalUnicast() -> bool

示例
ip("192.168.0.1").isGlobalUnicast() // true
(v0.29.0)
isLinkLocalMulticast 检查 IP 是否为链路本地多播地址。

签名
IP.isLinkLocalMulticast() -> bool

示例
ip("224.0.0.1").isLinkLocalMulticast() // true
(v0.29.0)
isLinkLocalUnicast 检查 IP 是否为链路本地单播地址。

签名
IP.isLinkLocalUnicast() -> bool

示例
ip("169.254.0.1").isLinkLocalUnicast() // true
(v0.29.0)
isLoopback 检查 IP 是否为环回地址。

签名
IP.isLoopback() -> bool

示例
ip("127.0.0.1").isLoopback() // true
(v0.29.0)
isMask 检查 CIDR 是否为有效的子网掩码。

签名
CIDR.isMask() -> bool

示例
cidr("255.255.255.0/24").isMask() // true
(v0.29.0)
isUnspecified 检查 IP 是否为未指定的地址(例如 0.0.0.0)。

签名
IP.isUnspecified() -> bool

示例
ip("0.0.0.0").isUnspecified() // true
(v0.29.0)
masked 返回经过掩码处理的 CIDR 块。

签名
CIDR.masked() -> CIDR

示例
cidr("192.168.0.1/24").masked() // 192.168.0.0/24
(v0.29.0)
prefixLength 返回 CIDR 块的前缀长度。

签名
CIDR.prefixLength() -> int

示例
cidr("192.168.0.0/24").prefixLength() // 24
(v0.29.0)
string 将 IP 或 CIDR 转换为字符串。

签名
string(IP) -> string
string(CIDR) -> string

示例
string(ip("192.168.0.1")) // "192.168.0.1"
(v0.29.0)

如何启用

  • Go:将 ext.Network() 传递给 cel.NewEnv()
  • C++:不支持。
  • Java:不支持。
  • Python:不支持。

5. 高级功能

高级功能摘要

功能 说明 Go C++ Java Python C
部分评估 使用缺失的输入进行评估;返回未知值或简化表达式。 ³
异步评估 扩展函数以非阻塞方式并发执行。
AST 验证器 在类型检查后对已检查的 AST 进行静态分析检查。
AST 优化器 AST 重写(常量折叠、内联、CSE),以提高性能。
CEL 政策编译器 将基于 YAML 的政策结构编译为标准 CEL AST。

³ Go 支持生成残差 AST(经过剪枝的 AST)。⁴ C++ 和 Java 支持在运行时返回 UnknownSet / CelUnknownSet,但不公开用于生成剩余 AST 的公共 API。⁵ Go 使用 AsyncBinding / AsyncOp 返回渠道。⁶ Java 使用 CelAsyncRuntime 返回 ListenableFuture

部分评估(未知)

部分评估是指在仅知道部分输入变量(实参)的情况下评估表达式。评估不会失败,而是会生成指示缺失内容或简化表达式的结果。

  • Go:完全支持。允许使用未知属性的模式定义 PartialActivation。评估返回一个 types.Unknown 值。Go 支持生成剩余 AST (Env.ResidualAst),这是一个经过剪枝的简化版 AST,仅包含无法求值的表达式部分。
  • C++:支持 Unknown 值。未知属性模式是通过 Activation::set_unknown_attribute_patterns 配置的。评估会返回 UnknownSet。公共 API 目前不公开剩余 AST 生成。
  • Java:支持通过传递给 Program.eval()PartialVars 进行部分评估。评估返回 CelUnknownSet。公共 API 目前不公开剩余 AST 生成。
  • Python / C:不提供原生支持。

异步评估

异步评估允许 CEL 表达式调用异步执行的函数(例如,发出 RPC 或数据库查询),并在结果可用之前阻塞评估,而不会阻塞主执行线程。

  • Go:通过 AsyncBindingAsyncOp 支持异步函数重载。异步函数会返回一个 Go 渠道 (<-chan ref.Val),而解释器会管理并发执行和同步。
  • Java:支持通过 CelAsyncRuntimeAsyncProgram 进行异步评估。它使用 ListenableFuture 表示待处理的值,并在 future 解析时自动驱动评估完成。
  • C++ / Python / C:无内置支持。

AST 验证器

验证器在类型检查后对已检查的 AST 执行静态分析,以在程序执行之前强制执行特定于网域的限制。

  • Go:支持 ASTValidator 接口。规范验证器包括 cel.validator.durationcel.validator.timestampcel.validator.matches(正则表达式)、cel.validator.homogeneous_literalscel.validator.comprehension_nesting_limit
  • C++:支持 cel::Validator。规范验证包括 AstDepthValidatorComprehensionNestingLimitValidatorDurationLiteralValidatorHomogeneousLiteralValidatorMatchesValidatorTimestampLiteralValidator
  • Java:支持 CelValidatorCelAstValidator。规范验证器包括 AstDepthLimitValidatorComprehensionNestingLimitValidatorDurationLiteralValidatorHomogeneousLiteralValidatorRegexLiteralValidatorTimestampLiteralValidator
  • Python / C:不支持直接使用。

AST 优化器

优化器会重写 AST 以提高执行性能。优化器分为两类:静态优化器和运行时优化器。C++、Java 和 Go 支持运行时优化。CEL Java 和 Go 还支持静态优化器。典型的优化包括常量折叠(预先评估具有常量输入值的子表达式)和消除公共子表达式 (CSE)。

  • Go:支持在编译/规划期间进行 AST 折叠。
  • C++:在规划时通过 cel::extensions::EnableConstantFolding 扩展程序支持常量折叠。
  • Java:支持 CelOptimizer 接口。规范优化器包括 ConstantFoldingOptimizer(可通过模拟部分评估来折叠短路分支)、InliningOptimizerSubexpressionOptimizer (CSE)。
  • Python / C:不支持直接使用。

CEL 政策编译器

CEL 政策是一种基于 YAML 的格式,用于将多个 CEL 表达式与变量、匹配块、条件输出和嵌套规则组合在一起。它专为复杂的政策引擎(如 Kubernetes 准入控制)而设计,在这些引擎中,单个 CEL 表达式会变得难以理解。

政策编译器会将这些 YAML 政策编译为单个标准 CEL AST,这意味着它们与标准 CEL 运行时完全兼容,并继承所有性能和安全保证。

  • Go:通过 third_party/cel/go/policy 提供支持。
  • C++:通过 third_party/cel/cpp/policy 支持。
  • Java:通过 third_party/java/cel/policy 提供支持。
  • Python / C:不支持直接使用。