Rex 编程语言语法参考(二):库语法
本文档覆盖 Rex 标准库与运行时库函数:按命名空间组织的内置标准库(math、io、file、os、path、string、random、collections、datetime、time、thread、re、mem、map、set)以及 FFI 扩展库(lib/json.rex、lib/http.rex、lib/crypto.rex)。 语言核心语法(类型、运算符、控制流、函数、数组、错误处理、泛型等)见《Rex 编程语言语法参考(一):语言基础语法》。 实战陷阱、性能优化、AOT、包管理、LSP、DAP、CLI 等工具与实现内容见《Rex 编程语言工具与实现参考》。
1. 标准库总览
标准库以命名空间形式内置在编译器中,无需 import,直接以 namespace.func(...) 调用:
| 命名空间 | 说明 | 示例 |
|---|
math | 数学运算 | math.sin(1.0)、math.sqrt(16.0) |
io | 输入输出 | io.read_line()、io.write("hi") |
file | 文件操作 | file.exists("a.txt")、file.read("a.txt") |
os | 操作系统 | os.getenv("PATH")、os.get_pid() |
path | 路径处理 | path.join("dir", "file.txt") |
string | 字符串操作 | string.upper("hi")、string.len("hi") |
re | 正则表达式 | re.match("^h", "hi")、re.replace("\\d", "#", s) |
random | 随机数 | random.random()、random.int(100) |
collections | 集合操作 | collections.sort_int(arr, len) |
datetime | 日期计算 | datetime.date()、datetime.from_ymd(2025, 7, 29) |
time | 时间函数 | time.now()、time.sleep(100) |
thread | 线程并发 | thread.spawn(fn, ...)、thread.join(h)、thread.atomic_add(c, 1) |
mem | 裸指针读写 | mem.read_i32(p, 0)、mem.write_float(p, 8, 3.14) |
map | 字典操作 | map.set(m, "k", v)、map.get(m, "k")、map.len(m) |
set | 集合操作 | set.create()、set.add(s, x)、set.has(s, x)、set.len(s) |
内存语义约定:返回 str 的运行时函数每次调用都会分配新字符串内存, 生命周期绑定当前函数栈帧,函数返回时自动释放(详见语言基础语法文档第 12 章「字符串内存管理」)。
2. 数学函数(Math)
通过 math. 命名空间使用,例如:math.sin(x: float) -> float
基础数学函数
| 函数 | 签名 | 描述 |
|---|
math.abs_int | (int) -> int | 整数绝对值 |
math.abs_float | (float) -> float | 浮点数绝对值 |
math.floor | (float) -> int | 向下取整 |
math.ceil | (float) -> int | 向上取整 |
math.round | (float) -> int | 四舍五入 |
math.trunc | (float) -> int | 截断小数部分 |
幂运算与对数
| 函数 | 签名 | 描述 |
|---|
math.pow | (float, float) -> float | 幂运算 base^exp |
math.sqrt | (float) -> float | 平方根 |
math.cbrt | (float) -> float | 立方根 |
math.exp | (float) -> float | e 的 x 次幂 |
math.log | (float) -> float | 自然对数 ln(x) |
math.log10 | (float) -> float | 以 10 为底的对数 |
math.log2 | (float) -> float | 以 2 为底的对数 |
math.log_base | (float, float) -> float | 以 base 为底的对数 |
三角函数
| 函数 | 签名 | 描述 |
|---|
math.sin | (float) -> float | 正弦函数(弧度) |
math.cos | (float) -> float | 余弦函数(弧度) |
math.tan | (float) -> float | 正切函数(弧度) |
math.asin | (float) -> float | 反正弦函数 |
math.acos | (float) -> float | 反余弦函数 |
math.atan | (float) -> float | 反正切函数 |
math.atan2 | (float, float) -> float | 双参数反正切函数 |
双曲函数
| 函数 | 签名 | 描述 |
|---|
math.sinh | (float) -> float | 双曲正弦 |
math.cosh | (float) -> float | 双曲余弦 |
math.tanh | (float) -> float | 双曲正切 |
math.asinh | (float) -> float | 反双曲正弦 |
math.acosh | (float) -> float | 反双曲余弦 |
math.atanh | (float) -> float | 反双曲正切 |
角度转换
| 函数 | 签名 | 描述 |
|---|
math.degrees | (float) -> float | 弧度转角度 |
math.radians | (float) -> float | 角度转弧度 |
符号与比较
| 函数 | 签名 | 描述 |
|---|
math.sign | (float) -> int | 返回符号 (-1, 0, 1) |
math.min | (float, float) -> float | 返回较小值 |
math.max | (float, float) -> float | 返回较大值 |
math.clamp | (float, float, float) -> float | 将值限制在 [lo, hi] 范围内 |
数学常数
| 函数 | 签名 | 描述 |
|---|
math.pi | () -> float | 圆周率 π |
math.e | () -> float | 自然常数 e |
math.inf | () -> float | 正无穷 |
math.nan | () -> float | NaN |
判断函数
| 函数 | 签名 | 描述 |
|---|
math.isfinite | (float) -> int | 检查是否为有限数 |
math.isinf | (float) -> int | 检查是否为无穷大 |
math.isnan | (float) -> int | 检查是否为 NaN |
其他数学函数
| 函数 | 签名 | 描述 |
|---|
math.modf | (float) -> float | 返回小数部分 |
math.fmod | (float, float) -> float | 浮点数取模 |
math.hypot | (float, float) -> float | 欧几里得距离 sqrt(x² + y²) |
math.ldexp | (float, int) -> float | x * 2^exp |
math.frexp | (float) -> float | 返回尾数 |
math.factorial | (int) -> int | 阶乘 |
math.gcd | (int, int) -> int | 最大公约数 |
math.lcm | (int, int) -> int | 最小公倍数 |
math.gamma | (float) -> float | Gamma 函数 |
math.lgamma | (float) -> float | Gamma 函数的自然对数 |
math.erf | (float) -> float | 误差函数 |
math.erfc | (float) -> float | 互补误差函数 |
入门示例:
rexfn main() {
// 基础:绝对值 / 取整
print(math.abs_int(-5)) // 5
print(math.floor(3.7)) // 3
print(math.ceil(3.2)) // 4
print(math.round(3.5)) // 4
// 幂运算与对数
print(math.sqrt(16.0)) // 4.0
print(math.pow(2.0, 10.0)) // 1024.0
print(math.log(math.e())) // 1.0
// 比较与限制
print(math.max(1.0, 5.0)) // 5.0
print(math.clamp(7.0, 0.0, 5.0)) // 5.0
// 整数运算
print(math.factorial(5)) // 120
print(math.gcd(12, 18)) // 6
print(math.pi()) // 3.141592653589793
}
提示:math 函数参数多为 float,传入整数字面量会自动转换;返回 int 的函数(floor/ceil/round/abs_int/factorial/gcd/lcm)可直接用于整数运算。
3. 字符串函数(String)
内存语义:返回 str 的字符串函数(upper/lower/strip/lstrip/rstrip/reverse/replace/substr/repeat/concat/from_char/from_int/from_float/dup)每次调用都会分配新字符串内存,生命周期绑定当前函数栈帧,函数返回时自动释放(详见语言基础语法文档第 12 章「字符串内存管理」)。 例外:find_char/find_sub 返回源字符串内部指针(不分配新内存);copy/cat 写入调用方提供的缓冲区;len/find/count/char_at 等返回数值,不涉及内存管理。
大小写转换
| 函数 | 签名 | 描述 |
|---|
string.upper | (str) -> str | 转换为大写 |
string.lower | (str) -> str | 转换为小写 |
去除空白
| 函数 | 签名 | 描述 |
|---|
string.strip | (str) -> str | 去除首尾空白 |
string.lstrip | (str) -> str | 去除前导空白 |
string.rstrip | (str) -> str | 去除尾部空白 |
字符串操作
| 函数 | 签名 | 描述 |
|---|
string.reverse | (str) -> str | 反转字符串 |
string.replace | (str, str, str) -> str | 替换所有匹配子串 |
string.substr | (str, int, int) -> str | 截取子串 |
string.repeat | (str, int) -> str | 重复字符串 n 次 |
string.concat | (str, str) -> str | 连接两个字符串 |
StringBuilder(高效循环拼接)
实战要点:string.concat 每次调用都全量 strdup 拷贝,循环拼接是严格的 O(n²)(文档已明确警告)。 需要循环组装大字符串(日志、JSON 响应、CSV 等)时,务必使用 StringBuilder: 追加过程零分配,仅在 tostr 时一次性分配结果,循环拼接降为 O(n)。
| 函数 | 签名 | 描述 |
|---|
string.builder_create | () -> int | 创建构建器,返回句柄(i64) |
string.builder_append | (int, str) -> void | 向构建器追加字符串(字节级追加,不产生中间分配) |
string.builder_tostr | (int) -> str | 取构建器当前内容,strdup 为帧管理字符串(后续 append 不影响已返回结果) |
string.builder_free | (int) -> void | 释放构建器 |
rexfn build_json() -> str {
let b: int = string.builder_create()
defer string.builder_free(b) // defer 保证释放
string.builder_append(b, "{\"items\": [")
var i: int = 0
while i < 10000 {
string.builder_append(b, string.from_int(i))
string.builder_append(b, ",")
i = i + 1
}
string.builder_append(b, "]}")
return string.builder_tostr(b) // 仅此处分配一次,O(n)
}
- 句柄生命周期由用户管理:建议
defer string.builder_free(b),忘记释放会产生小对象泄漏 builder_tostr 返回的字符串参与帧管理,随函数返回自动释放;返回值可安全跨函数返回- 构建器不是线程安全的:单线程内使用;跨线程请用线程数组快照或互斥锁
字符串查找
| 函数 | 签名 | 描述 |
|---|
string.find | (str, str) -> int | 查找子串位置(未找到返回 -1);返回 Unicode 码点索引(非字节偏移),UTF-8 中文按 1 个码点计 |
string.rfind | (str, str) -> int | 从右向左查找子串位置(返回码点索引) |
string.count | (str, str) -> int | 统计子串出现次数 |
string.contains | (str, str) -> int | 检查是否包含子串 |
索引单位陷阱:string.find/rfind/char_at 的索引是 Unicode 码点索引,与 string.substr(按码点截取)一致; 但 string.len 返回的是字节数(strlen)。两者单位不同,不能混用——string.substr(s, string.find(s, x), string.len(x)) 在含中文时长度会算错 (字节数 > 码点数)。涉及非 ASCII 文本,长度统一用 string.codepoint_len,勿用 string.len 作为索引/长度参数。
字符串判断
| 函数 | 签名 | 描述 |
|---|
string.isalpha | (str) -> int | 检查是否只包含字母 |
string.isdigit | (str) -> int | 检查是否只包含数字 |
string.isalnum | (str) -> int | 检查是否只包含字母和数字 |
string.isspace | (str) -> int | 检查是否只包含空白字符 |
string.isupper | (str) -> int | 检查是否全为大写 |
string.islower | (str) -> int | 检查是否全为小写 |
string.isempty | (str) -> int | 检查是否为空 |
string.startswith | (str, str) -> int | 检查是否以指定前缀开头 |
string.endswith | (str, str) -> int | 检查是否以指定后缀结尾 |
字符串比较
| 函数 | 签名 | 描述 |
|---|
string.len | (str) -> int | 获取字符串字节长度(strlen,不含结尾空字符);UTF-8 中文每字 3 字节 |
string.codepoint_len | (str) -> int | 获取字符串的 Unicode 码点数量(UTF-8 解码后);"中文" 返回 2 |
string.compare | (str, str) -> int | 比较两个字符串(返回 -1, 0, 1) |
string.equals | (str, str) -> int | 检查两个字符串是否相等 |
string.cmp | (str, str) -> int | C 风格字符串比较(strcmp) |
string.find_char | (str, int) -> str | 查找字符,返回从该字符开始的子串指针 |
string.find_sub | (str, str) -> str | 查找子串,返回从子串开始的指针 |
string.copy | (str, str) -> str | 复制字符串到目标缓冲区(strcpy) |
string.cat | (str, str) -> str | 追加字符串到目标缓冲区(strcat) |
string.dup | (str) -> str | 复制字符串(动态分配,strdup) |
字符操作
| 函数 | 签名 | 描述 |
|---|
string.char_at | (str, int) -> int | 获取指定位置(码点索引)的字符码点;越界返回 0 |
string.from_char | (int) -> str | 从字符码创建单字符字符串 |
string.first | (str) -> int | 获取第一个字符 |
string.last | (str) -> int | 获取最后一个字符 |
类型转换
| 函数 | 签名 | 描述 |
|---|
string.toint | (str) -> int | 字符串转整数 |
string.tofloat | (str) -> float | 字符串转浮点数 |
string.from_int | (int) -> str | 整数转字符串 |
string.from_float | (float) -> str | 浮点数转字符串 |
入门示例:
rexfn main() {
// 大小写与去除空白
print(string.upper("hello")) // HELLO
print(string.lower("WORLD")) // world
print(string.strip(" hi ")) // hi
// 截取 / 替换 / 重复
print(string.substr("hello", 1, 3)) // ell
print(string.replace("a-b-c", "-", "+")) // a+b+c
print(string.repeat("ab", 3)) // ababab
// 查找与判断(返回 1/0)
print(string.find("hello", "ll")) // 2
print(string.contains("hello", "ell")) // 1
print(string.startswith("hello", "he")) // 1
// 类型转换
print(string.toint("42") + 1) // 43
print(string.from_int(7)) // 7
print(string.from_float(3.5)) // 3.5
}
提示:find/rfind/char_at/substr 使用 Unicode 码点索引,而 string.len 返回字节数;涉及中文时统一用 string.codepoint_len 取长度(见上方「索引单位陷阱」)。
4. I/O 函数(IO)
标准输入
| 函数 | 签名 | 描述 |
|---|
io.read_line | () -> str | 从标准输入读取一行 |
io.read_int | () -> int | 从标准输入读取整数 |
io.read_float | () -> float | 从标准输入读取浮点数 |
io.read_char | () -> int | 从标准输入读取一个字符 |
io.read_all | () -> str | 从标准输入读取所有内容 |
标准输出
| 函数 | 签名 | 描述 |
|---|
io.write_line | (str) -> int | 写入一行到标准输出 |
io.write | (str) -> int | 写入到标准输出(不带换行) |
io.write_int | (int) -> int | 写入整数到标准输出 |
io.write_float | (float) -> int | 写入浮点数到标准输出 |
io.write_char | (int) -> int | 写入字符到标准输出 |
标准错误
| 函数 | 签名 | 描述 |
|---|
io.error_line | (str) -> int | 写入一行到标准错误 |
io.error | (str) -> int | 写入到标准错误(不带换行) |
流式文件操作
| 函数 | 签名 | 描述 |
|---|
io.open | (str, str) -> int | 打开文件,返回文件句柄 |
io.close | (int) -> int | 关闭文件 |
io.file_read_line | (int) -> str | 从文件读取一行 |
io.file_read_all | (int) -> str | 读取文件全部内容 |
io.file_write | (int, str) -> int | 写入文件 |
io.file_write_line | (int, str) -> int | 写入一行到文件 |
io.file_eof | (int) -> int | 检查是否到达文件末尾 |
io.file_flush | (int) -> int | 刷新文件缓冲区 |
批量操作
| 函数 | 签名 | 描述 |
|---|
io.read_lines | (str) -> str | 读取文件所有行 |
io.write_lines | (str, str) -> int | 写入多行到文件 |
io.count_lines | (str) -> int | 统计文件行数 |
入门示例(命令行问答小程序):
rexfn main() {
io.write_line("请输入你的名字:")
let name: str = io.read_line()
io.write("你好, ")
io.write_line(name) // 输出到标准输出
io.write_line("请输入一个整数:")
let n: int = io.read_int()
io.write_line(string.concat("n * 2 = ", string.from_int(n * 2)))
io.error_line("这是一条错误信息") // 写入标准错误
}
提示:io.write 不带换行、io.write_line 自动追加换行;read_int/read_float 会跳过空白直接解析数值。流式文件句柄操作(io.open/file_read_line/close)适合逐行处理大文件,见下节 file 的整读整写用法。
5. 文件函数(File)
文件读写
| 函数 | 签名 | 描述 |
|---|
file.read | (str) -> str | 读取文件全部内容 |
file.read_bytes | (str, ptr, int) -> int | 读取文件到缓冲区 |
file.write | (str, str) -> int | 写入文件(覆盖) |
file.append | (str, str) -> int | 追加写入文件 |
file.write_bytes | (str, ptr, int) -> int | 写入字节数组 |
文件信息
| 函数 | 签名 | 描述 |
|---|
file.exists | (str) -> int | 检查文件是否存在 |
file.size | (str) -> int | 获取文件大小 |
file.is_dir | (str) -> int | 检查是否为目录 |
file.is_file | (str) -> int | 检查是否为文件 |
文件操作
| 函数 | 签名 | 描述 |
|---|
file.delete | (str) -> int | 删除文件 |
file.copy | (str, str) -> int | 复制文件 |
file.move | (str, str) -> int | 移动文件 |
file.rename | (str, str) -> int | 重命名文件 |
目录操作
| 函数 | 签名 | 描述 |
|---|
file.mkdir | (str) -> int | 创建目录 |
file.rmdir | (str) -> int | 删除空目录 |
file.list | (str) -> str | 列出目录内容 |
file.list_files | (str) -> str | 列出目录中的文件 |
file.list_dirs | (str) -> str | 列出目录中的子目录 |
路径操作
| 函数 | 签名 | 描述 |
|---|
file.getcwd | () -> str | 获取当前工作目录 |
file.chdir | (str) -> int | 切换工作目录 |
file.abs_path | (str) -> str | 获取绝对路径 |
file.join | (str, str) -> str | 连接路径 |
file.basename | (str) -> str | 获取文件名 |
file.dirname | (str) -> str | 获取目录名 |
file.extname | (str) -> str | 获取扩展名 |
入门示例:
rexfn main() {
// 写入 / 读取
file.write("data.txt", "hello rex")
print(file.exists("data.txt")) // 1
print(file.read("data.txt")) // hello rex
// 追加与信息
file.append("data.txt", "\nline2")
print(file.size("data.txt")) // 字节数(含换行)
print(file.is_file("data.txt")) // 1
// 文件操作
file.rename("data.txt", "data2.txt")
file.delete("data2.txt")
// 目录操作
file.mkdir("mydir")
print(file.is_dir("mydir")) // 1
file.rmdir("mydir")
// 路径操作
print(file.basename("a/b/c.txt")) // c.txt
print(file.extname("a/b/c.txt")) // .txt
}
提示:file.read/file.write 一次读写整个文件,适合配置文件、小文本;大文件逐行处理用 io.open + io.file_read_line(见第 4 章)。返回的字符串由帧自动管理,无需手动释放。
6. 操作系统函数(OS)
环境变量
| 函数 | 签名 | 描述 |
|---|
os.getenv | (str) -> str | 获取环境变量 |
os.setenv | (str, str) -> int | 设置环境变量 |
os.unsetenv | (str) -> int | 删除环境变量 |
os.getenv_keys | () -> str | 获取所有环境变量名 |
用户信息
| 函数 | 签名 | 描述 |
|---|
os.get_username | () -> str | 获取当前用户名 |
os.get_homedir | () -> str | 获取用户主目录 |
os.get_user_cache_dir | () -> str | 获取用户缓存目录 |
os.get_user_config_dir | () -> str | 获取用户配置目录 |
os.get_user_data_dir | () -> str | 获取用户数据目录 |
系统信息
| 函数 | 签名 | 描述 |
|---|
os.get_platform | () -> str | 获取操作系统平台名称 |
os.get_system | () -> str | 获取操作系统名称 |
os.get_release | () -> str | 获取操作系统版本 |
os.get_version | () -> str | 获取操作系统详细版本 |
os.get_machine | () -> str | 获取机器架构 |
os.get_processor | () -> str | 获取处理器信息 |
os.get_hostname | () -> str | 获取主机名 |
os.get_cpu_count | () -> int | 获取 CPU 核心数 |
os.get_loadavg | () -> str | 获取系统负载平均值 |
进程管理
| 函数 | 签名 | 描述 |
|---|
os.get_pid | () -> int | 获取当前进程 ID |
os.get_ppid | () -> int | 获取父进程 ID |
os.exec | (str) -> int | 执行系统命令并返回退出码 |
os.exec_output | (str) -> str | 执行系统命令并返回输出 |
os.sleep | (int) -> int | 休眠指定毫秒数 |
os.exit | (int) -> void | 退出程序 |
临时文件
| 函数 | 签名 | 描述 |
|---|
os.temp_dir | () -> str | 获取临时目录路径 |
os.temp_filename | () -> str | 生成临时文件名 |
os.temp_dirname | () -> str | 生成临时目录名 |
磁盘空间
| 函数 | 签名 | 描述 |
|---|
os.disk_free | (str) -> int | 获取磁盘剩余空间 |
os.disk_total | (str) -> int | 获取磁盘总空间 |
os.disk_used | (str) -> int | 获取磁盘已用空间 |
路径扩展
| 函数 | 签名 | 描述 |
|---|
os.expanduser | (str) -> str | 扩展路径中的 ~ |
os.expandvars | (str) -> str | 扩展路径中的环境变量 |
权限与属性
| 函数 | 签名 | 描述 |
|---|
os.chmod | (str, int) -> int | 修改文件权限 |
os.get_modtime | (str) -> int | 获取文件修改时间 |
os.set_modtime | (str, int) -> int | 设置文件修改时间 |
命令行参数
| 函数 | 签名 | 描述 |
|---|
os.get_argc | () -> int | 获取命令行参数数量 |
os.get_arg | (int) -> str | 获取指定索引的命令行参数 |
os.get_args | () -> str | 获取所有命令行参数 |
实用函数
| 函数 | 签名 | 描述 |
|---|
os.get_random_bytes | (int) -> str | 获取随机字节(十六进制) |
os.is_admin | () -> int | 检查是否以管理员权限运行 |
入门示例:
rexfn main() {
// 环境变量
os.setenv("MY_VAR", "123")
print(os.getenv("MY_VAR")) // 123
// 系统信息
print(os.get_platform()) // 例如 win32
print(os.get_cpu_count()) // 例如 8
print(os.get_pid()) // 当前进程 ID
// 执行系统命令
let out: str = os.exec_output("echo hello")
print(out) // hello
}
提示:os.exec 返回命令退出码、os.exec_output 返回命令输出文本;os.sleep(ms) 与 time.sleep(ms) 等价。注意 os.setenv 只影响当前进程的环境变量。
7. 随机数函数(Random)
基础随机数
| 函数 | 签名 | 描述 |
|---|
random.random | () -> float | 返回 [0.0, 1.0) 范围内的随机浮点数 |
random.int | (int) -> int | 返回 [0, max) 范围内的随机整数 |
random.range | (int, int) -> int | 返回 [min, max) 范围内的随机整数 |
范围随机数
| 函数 | 签名 | 描述 |
|---|
random.uniform | (float, float) -> float | 返回 [min, max) 范围内的随机浮点数 |
random.int_range | (int, int) -> int | 返回 [min, max] 范围内的随机整数(包含两端) |
随机种子
| 函数 | 签名 | 描述 |
|---|
random.seed | (int) -> void | 设置随机数生成器种子 |
特殊分布
| 函数 | 签名 | 描述 |
|---|
random.gauss | (float, float) -> float | 生成高斯分布随机数 |
random.expovariate | (float) -> float | 生成指数分布随机数 |
random.triangular | (float, float, float) -> float | 生成三角分布随机数 |
入门示例:
rexfn main() {
random.seed(42) // 固定种子,结果可复现
print(random.random()) // [0.0, 1.0) 随机浮点
print(random.int(100)) // [0, 100) 随机整数
print(random.range(10, 20)) // [10, 20) 随机整数
print(random.int_range(1, 6)) // [1, 6],掷骰子
print(random.uniform(0.0, 1.0)) // [0.0, 1.0) 均匀浮点
}
提示:不调用 random.seed 时以系统熵初始化,每次运行结果不同;需要可复现的测试数据(如单元测试)时先 random.seed(n)。
8. 日期函数(Datetime)
所有日期函数使用 Unix 时间戳(秒)作为日期表示。
日期创建
| 函数 | 签名 | 描述 |
|---|
datetime.date | () -> int | 获取当前日期时间戳 |
datetime.from_ymd | (int, int, int) -> int | 从年月日创建日期 |
datetime.from_timestamp | (int) -> int | 从时间戳创建日期 |
日期加法
| 函数 | 签名 | 描述 |
|---|
datetime.add_days | (int, int) -> int | 日期加天数 |
datetime.add_weeks | (int, int) -> int | 日期加周数 |
datetime.add_months | (int, int) -> int | 日期加月数(自动处理月末) |
datetime.add_years | (int, int) -> int | 日期加年数 |
日期减法
| 函数 | 签名 | 描述 |
|---|
datetime.sub_days | (int, int) -> int | 日期减天数 |
datetime.sub_weeks | (int, int) -> int | 日期减周数 |
datetime.sub_months | (int, int) -> int | 日期减月数 |
datetime.sub_years | (int, int) -> int | 日期减年数 |
日期差计算
| 函数 | 签名 | 描述 |
|---|
datetime.diff_days | (int, int) -> int | 计算两个日期之间的天数差 |
datetime.diff_weeks | (int, int) -> int | 计算两个日期之间的周数差 |
datetime.diff_months | (int, int) -> int | 计算两个日期之间的月数差 |
日期比较
| 函数 | 签名 | 描述 |
|---|
datetime.compare | (int, int) -> int | 比较两个日期(返回 -1, 0, 1) |
datetime.is_before | (int, int) -> int | 判断 date1 是否在 date2 之前 |
datetime.is_after | (int, int) -> int | 判断 date1 是否在 date2 之后 |
datetime.is_same | (int, int) -> int | 判断两个日期是否相同 |
datetime.is_between | (int, int, int) -> int | 判断日期是否在范围内 |
日期范围判断
| 函数 | 签名 | 描述 |
|---|
datetime.is_weekend | (int) -> int | 判断是否为周末 |
datetime.is_weekday | (int) -> int | 判断是否为工作日 |
datetime.is_leap_year_for | (int) -> int | 判断指定年份是否为闰年 |
datetime.days_in_month | (int, int) -> int | 获取指定月份的天数 |
datetime.is_last_day_of_month | (int) -> int | 判断是否为当月最后一天 |
datetime.is_first_day_of_month | (int) -> int | 判断是否为当月第一天 |
日期获取
| 函数 | 签名 | 描述 |
|---|
datetime.get_year | (int) -> int | 获取年份 |
datetime.get_month | (int) -> int | 获取月份 |
datetime.get_day | (int) -> int | 获取日期 |
datetime.get_weekday | (int) -> int | 获取星期几 (1=周一, 7=周日) |
datetime.get_yearday | (int) -> int | 获取年份第几天 |
datetime.get_week_of_year | (int) -> int | 获取年份第几周 |
datetime.get_quarter | (int) -> int | 获取季度 |
日期边界
| 函数 | 签名 | 描述 |
|---|
datetime.start_of_week | (int) -> int | 获取本周周一 |
datetime.end_of_week | (int) -> int | 获取本周周日 |
datetime.start_of_month | (int) -> int | 获取本月第一天 |
datetime.end_of_month | (int) -> int | 获取本月最后一天 |
datetime.start_of_year | (int) -> int | 获取本年第一天 |
datetime.end_of_year | (int) -> int | 获取本年最后一天 |
特殊日期判断
| 函数 | 签名 | 描述 |
|---|
datetime.is_today | (int) -> int | 判断是否为今天 |
datetime.is_yesterday | (int) -> int | 判断是否为昨天 |
datetime.is_tomorrow | (int) -> int | 判断是否为明天 |
datetime.days_until | (int, int) -> int | 计算距离目标日期还有多少天 |
datetime.days_since | (int, int) -> int | 计算从目标日期已过多少天 |
入门示例:
rexfn main() {
// 创建日期(内部为 Unix 时间戳,秒)
let d: int = datetime.from_ymd(2025, 7, 29)
print(datetime.get_year(d)) // 2025
print(datetime.get_month(d)) // 7
print(datetime.get_day(d)) // 29
print(datetime.get_weekday(d)) // 2(2025-07-29 是周二)
// 日期运算
let next: int = datetime.add_days(d, 7)
print(datetime.diff_days(next, d)) // 7
// 判断与边界
print(datetime.is_weekend(d)) // 0(周二)
print(datetime.is_leap_year_for(2024)) // 1
print(datetime.days_in_month(2024, 2)) // 29(闰年 2 月)
print(datetime.get_quarter(d)) // 3(第三季度)
}
提示:所有日期函数都以秒级时间戳(int)表示日期,读取字段用 get_year/get_month/get_day 等;需要格式化输出字符串用 time.format_datetime()(见第 10 章)。
9. 集合函数(Collections)
数组排序
| 函数 | 签名 | 描述 |
|---|
collections.sort_int | (ptr, int) -> void | 原地排序整数数组(升序) |
collections.sort_desc_int | (ptr, int) -> void | 原地排序整数数组(降序) |
collections.sort_float | (ptr, int) -> void | 原地排序浮点数数组 |
collections.sorted_int | (ptr, int) -> ptr | 返回排序后的新数组 |
数组反转
| 函数 | 签名 | 描述 |
|---|
collections.reverse_int | (ptr, int) -> void | 原地反转整数数组 |
collections.reversed_int | (ptr, int) -> ptr | 返回反转后的新数组 |
数组填充
| 函数 | 签名 | 描述 |
|---|
collections.fill_int | (ptr, int, int) -> void | 用指定值填充数组 |
collections.fill_range_int | (ptr, int, int, int) -> void | 填充指定范围 |
数组复制
| 函数 | 签名 | 描述 |
|---|
collections.copy_int | (ptr, int) -> ptr | 复制数组 |
collections.copy_range_int | (ptr, int, int) -> ptr | 复制指定范围 |
数组去重
| 函数 | 签名 | 描述 |
|---|
collections.unique_int | (ptr, int) -> ptr | 返回去重后的新数组 |
collections.unique_count_int | (ptr, int) -> int | 返回唯一元素个数 |
数组查找
| 函数 | 签名 | 描述 |
|---|
collections.find_int | (ptr, int, int) -> int | 查找值,返回索引 |
collections.find_last_int | (ptr, int, int) -> int | 从右查找值,返回索引 |
collections.count_int | (ptr, int, int) -> int | 统计值出现次数 |
collections.contains_int | (ptr, int, int) -> int | 检查是否包含值 |
二分查找
| 函数 | 签名 | 描述 |
|---|
collections.binary_search_int | (ptr, int, int) -> int | 二分查找,返回索引 |
collections.lower_bound_int | (ptr, int, int) -> int | 返回第一个不小于 value 的索引 |
collections.upper_bound_int | (ptr, int, int) -> int | 返回第一个大于 value 的索引 |
数组统计
| 函数 | 签名 | 描述 |
|---|
collections.min_int | (ptr, int) -> int | 返回最小值 |
collections.max_int | (ptr, int) -> int | 返回最大值 |
collections.sum_int | (ptr, int) -> int | 返回元素之和 |
collections.avg_int | (ptr, int) -> float | 返回平均值 |
数组变换
| 函数 | 签名 | 描述 |
|---|
collections.map_int | (ptr, int, int) -> ptr | 每个元素乘以因子 |
collections.filter_positive_int | (ptr, int) -> ptr | 过滤出正数 |
collections.filter_negative_int | (ptr, int) -> ptr | 过滤出负数 |
数组合并
| 函数 | 签名 | 描述 |
|---|
collections.merge_int | (ptr, int, ptr, int) -> ptr | 合并两个数组 |
collections.merge_sorted_int | (ptr, int, ptr, int) -> ptr | 合并两个已排序数组 |
数组切片
| 函数 | 签名 | 描述 |
|---|
collections.slice_int | (ptr, int, int) -> ptr | 返回数组切片 |
数组比较
| 函数 | 签名 | 描述 |
|---|
collections.equals_int | (ptr, int, ptr, int) -> int | 比较两个数组是否相等 |
计数器功能
| 函数 | 签名 | 描述 |
|---|
collections.counter_most_common | (ptr, int, int) -> ptr | 返回出现次数最多的前 n 个元素 |
collections.counter_count | (ptr, int, int) -> int | 统计指定值出现次数 |
入门示例:
rexfn main() {
var arr: int[] = [64, 34, 25, 12, 22, 11]
// 原地排序(升序),结果写回原数组
collections.sort_int(arr, 6)
print(arr[0]) // 11(最小值)
print(arr[5]) // 64(最大值)
// 查找与统计
print(collections.find_int(arr, 6, 25)) // 2
print(collections.min_int(arr, 6)) // 11
print(collections.max_int(arr, 6)) // 64
print(collections.sum_int(arr, 6)) // 168
}
提示:collections 的入参是「数组 + 元素个数」两个参数(数组按指针传递);sort_*/reverse_*/fill_* 为原地操作,sorted_*/reversed_*/slice_*/unique_* 返回新数组(由帧自动管理)。
10. 时间函数(Time)
| 函数 | 签名 | 描述 |
|---|
time.now | () -> int | 当前时间戳(毫秒) |
time.clock | () -> float | 高精度时钟(秒) |
time.elapsed | (int) -> int | 从 start 开始的已过毫秒数 |
time.sleep | (int) -> void | 休眠指定毫秒数 |
time.sleep_seconds | (float) -> void | 休眠指定秒数 |
time.unix | () -> int | Unix 时间戳(秒) |
time.unix_nano | () -> int | Unix 时间戳(纳秒) |
time.from_unix | (int) -> int | Unix 秒转毫秒 |
time.to_unix | (int) -> int | 毫秒转 Unix 秒 |
time.year | () -> int | 当前年份 |
time.month | () -> int | 当前月份 |
time.day | () -> int | 当前日 |
time.hour | () -> int | 当前小时 |
time.minute | () -> int | 当前分钟 |
time.second | () -> int | 当前秒 |
time.millisecond | () -> int | 当前毫秒 |
time.weekday | () -> int | 当前星期几 |
time.yearday | () -> int | 当前年内第几天 |
time.is_leap_year | () -> int | 当前年是否为闰年 |
time.timezone_offset | () -> int | 时区偏移 |
time.utc_offset | () -> int | UTC 偏移 |
time.stopwatch_start | () -> float | 启动秒表 |
time.stopwatch_elapsed | (float) -> float | 秒表已过秒数 |
time.stopwatch_elapsed_ms | (float) -> int | 秒表已过毫秒数 |
time.cpu_time | () -> float | CPU 时间 |
time.thread_time | () -> float | 线程时间 |
time.millis_to_seconds | (int) -> float | 毫秒转秒 |
time.seconds_to_millis | (float) -> int | 秒转毫秒 |
time.format_date | () -> str | 格式化日期 |
time.format_time | () -> str | 格式化时间 |
time.format_datetime | () -> str | 格式化日期时间 |
入门示例:
rexfn main() {
let start: int = time.now() // 毫秒时间戳
print(time.year()) // 当前年份
print(time.hour()) // 当前小时
print(time.format_datetime()) // 如 2026-08-05 14:30:00
time.sleep(100) // 休眠 100 毫秒
print(time.elapsed(start)) // >= 100
}
提示:time.now() 返回毫秒时间戳、time.unix() 返回秒时间戳,time.elapsed(start) 是常见的耗时统计组合(见基础语法文档第 24 章「斐波那契数列」示例);秒表用 stopwatch_start() + stopwatch_elapsed_ms()。
11. 线程并发函数(Thread)
Rex 的并发模型是真实操作系统线程:thread.spawn 在 OS 线程中执行 JIT 编译的 Rex 函数, 配合 thread.join 回收结果、互斥锁保证临界区互斥、原子计数器做无锁累加。
通过 thread. 命名空间使用,无需 import。
线程创建与回收
| 函数 | 签名 | 描述 |
|---|
thread.spawn | (fn, args...) -> int | 创建 OS 线程执行 fn,返回线程句柄;编译器自动生成线程入口包装函数(帧管理、参数搬运、结果写回) |
thread.join | (int) -> int | 等待线程结束并返回返回值(int/bool;void 返回 0) |
thread.join_float | (int) -> float | 等待线程结束并返回 float 返回值 |
thread.sleep | (int) -> void | 当前线程休眠(毫秒) |
thread.current_id | () -> int | 返回当前线程标识 |
rexfn worker(a: int, b: int) -> int {
return a * 1000 + b
}
fn float_worker(x: float) -> float {
return x * 2.5
}
fn main() {
let h1: int = thread.spawn(worker, 1, 2)
let r1: int = thread.join(h1) // 1002
// 多线程并行
let ha: int = thread.spawn(worker, 1, 1)
let hb: int = thread.spawn(worker, 2, 2)
let total: int = thread.join(ha) + thread.join(hb) // 3003
// float 返回值用 join_float
let hf: int = thread.spawn(float_worker, 3.5)
let rf: float = thread.join_float(hf) // 8.75
// 线程内休眠(必须 join,见下方注意事项)
let hs: int = thread.spawn(worker, 9, 9)
thread.sleep(100)
thread.join(hs)
}
互斥锁
| 函数 | 签名 | 描述 |
|---|
thread.mutex_create | () -> int | 创建互斥锁,返回句柄 |
thread.mutex_lock | (int) -> void | 加锁(阻塞等待;等待期间释放 GIL,其他线程可并行) |
thread.mutex_unlock | (int) -> void | 解锁 |
thread.mutex_destroy | (int) -> void | 销毁互斥锁 |
rexlet mid: int = thread.mutex_create()
let h1: int = thread.spawn(mutex_worker, mid)
let h2: int = thread.spawn(mutex_worker, mid)
thread.join(h1)
thread.join(h2)
thread.mutex_destroy(mid)
原子计数器(无锁累加)
| 函数 | 签名 | 描述 |
|---|
thread.counter_create | () -> ptr | 分配一个 8 字节原子计数器,返回指针 |
thread.atomic_add | (ptr, int) -> int | 原子加(LLVM atomicrmw),返回旧值 |
thread.atomic_get | (ptr) -> int | 原子读取当前值 |
thread.counter_free | (ptr) -> void | 释放计数器 |
rexfn counter_worker(n: int, counter: ptr) -> int {
var i: int = 0
while i < n {
thread.atomic_add(counter, 1)
i = i + 1
}
return 0
}
let counter: ptr = thread.counter_create()
let h1: int = thread.spawn(counter_worker, 1000, counter)
let h2: int = thread.spawn(counter_worker, 1000, counter)
let h3: int = thread.spawn(counter_worker, 1000, counter)
thread.join(h1)
thread.join(h2)
thread.join(h3)
print(thread.atomic_get(counter)) // 3000
thread.counter_free(counter)
限制与注意事项
- 线程函数签名:
thread.spawn 的目标函数必须已声明(在调用点之前定义),
参数仅限 int/float/bool/ptr 或一维标量数组(int[]/float[]/bool[]), 返回值仅限 int/float/bool/void,最多 8 个参数。 字符串、多维数组、结构体数组等帧管理内存禁止跨线程传递(编译期报错)。
- 数组参数 = 快照拷贝(深拷贝):
thread.spawn(fn, arr, ...) 传递数组时,
编译器在 spawn 调用点深拷贝一份数组快照,子线程读写的是自己的副本, 与主线程数据完全隔离,天然线程安全;子线程返回后快照自动释放。 大数组拷贝有 O(n) 开销,适合分片并行(map-reduce)等"只读分发给子线程"场景; 需要跨线程共享可变数据的场景请改用 ptr + 原子计数器/互斥锁。
- 线程帧隔离:每个线程拥有独立的字符串帧池与栈回溯(线程本地存储),线程入口自动
push/pop,互不干扰。线程内未捕获异常与主线程行为一致(打印回溯并终止进程)。
- 必须 join:所有
spawn 的线程必须在 main 返回前 thread.join,否则进程退出时
JIT 模块可能被回收,导致仍在运行的线程崩溃。
- 内存所有权:
ptr 参数(如原子计数器)指向的内存必须由使用者保证在线程运行期间
有效(如 counter_free 在所有线程 join 之后再调用)。
- 真实并行:JIT 原生代码通过 ctypes 调用执行时释放 GIL,多个线程真正多核并行;
线程内调用 Python 侧运行时函数(字符串操作等)时会短暂重获 GIL。
12. 正则表达式函数(Regex)
对标 Python re 模块的核心功能。通过 re. 命名空间使用,无需 import。 底层基于 Python 的 re 模块实现,支持标准正则语法(\d、\w、[]、() 等)。
内存语义:返回 str 的正则函数(find/findall/replace/split/escape)每次调用都会 分配新字符串内存,生命周期绑定当前函数栈帧,函数返回时自动释放(见语言基础语法文档第 12 章)。 findall/split 返回多个结果时以换行符 \n 分隔(约定同 file.list)。
匹配判断(返回 1/0)
| 函数 | 签名 | 描述 |
|---|
re.match | (str, str) -> int | 从字符串开头匹配,成功返回 1,失败返回 0(对标 re.match) |
re.search | (str, str) -> int | 在字符串任意位置搜索,成功返回 1,失败返回 0(对标 re.search) |
re.fullmatch | (str, str) -> int | 整个字符串必须完全匹配,成功返回 1,失败返回 0(对标 re.fullmatch) |
rexre.match("Hello", "Hello World") // 1
re.match("World", "Hello World") // 0(match 只从头匹配)
re.search("World", "Hello World") // 1
re.fullmatch("Hello World", "Hello World") // 1
re.fullmatch("Hello", "Hello World") // 0
匹配提取
| 函数 | 签名 | 描述 |
|---|
re.find | (str, str) -> str | 返回第一个匹配的子串,未找到返回空字符串 |
re.findall | (str, str) -> str | 返回所有匹配的子串,以 \n 分隔(对标 re.findall) |
re.replace | (str, str, str) -> str | 将文本中所有匹配替换为指定文本(对标 re.sub) |
re.split | (str, str) -> str | 按正则表达式分割字符串,各段以 \n 分隔(对标 re.split) |
rexre.find("\\d+", "abc123def456") // "123"
re.findall("\\d+", "a1b22c333") // "1\n22\n333"
re.replace("\\d+", "#", "a1b22c333") // "a#b#c#"
re.split("[,\\s]+", "a, b,c d") // "a\nb\nc\nd"
工具函数
| 函数 | 签名 | 描述 |
|---|
re.escape | (str) -> str | 转义正则表达式中的特殊字符,使其按字面量匹配(对标 re.escape) |
re.is_valid | (str) -> int | 检查模式是否合法,合法返回 1,非法(如未闭合 [)返回 0 |
rexre.escape("a.b+c") // "a\.b\+c"
re.is_valid("\\d+") // 1
re.is_valid("[") // 0
与 Python re 的差异
- 匹配判断类函数返回
int(1/0)而非 Match 对象; - 不支持 flags(如
re.IGNORECASE),默认使用普通匹配; findall/split 的多结果以 \n 分隔的字符串返回,而非列表;- 无效模式不会抛异常:匹配类函数返回 0/空串,
re.is_valid 可显式检查。
13. 内存读写函数(mem)
实战要点:Rex 的 ptr 是裸 i8*,语言内无法解引用 C 结构体字段。 mem 命名空间提供按偏移读写裸指针内存的能力,简单 C 结构体字段访问 无需再编写 C shim(配合语言基础语法文档第 17 章 FFI 使用)。
| 函数 | 签名 | 描述 |
|---|
mem.read_i32 | (ptr, int) -> int | 读取 ptr+offset 处的 32 位有符号整数 |
mem.read_i64 | (ptr, int) -> int | 读取 ptr+offset 处的 64 位有符号整数 |
mem.read_float | (ptr, int) -> float | 读取 ptr+offset 处的 64 位双精度浮点数 |
mem.read_str | (ptr) -> str | 读取以 \0 结尾的 C 字符串(strdup 到帧池,自动管理) |
mem.read_bytes | (ptr, int) -> str | 读取 len 字节(strdup 到帧池) |
mem.write_i32 | (ptr, int, int) -> void | 写入 32 位有符号整数 |
mem.write_i64 | (ptr, int, int) -> void | 写入 64 位有符号整数 |
mem.write_float | (ptr, int, float) -> void | 写入 64 位双精度浮点数 |
辅助转换:整数地址与 ptr 互相转换用 as(inttoptr/ptrtoint): mem.read_str(name_ptr as ptr)、let addr: int = some_ptr as int。
rex// 读取 cJSON 节点(C 结构体)的 type 字段:next=0, prev=8, child=16, type=24
let root: ptr = json_parse(text)
let type_field: int = mem.read_i32(root, 24)
// 读取字符串节点的 valuestring(char* 指针,偏移 32)
let name_node: ptr = json_get(root, "name")
let name_ptr: int = mem.read_i64(name_node, 32) // char* 地址
let name_val: str = mem.read_str(name_ptr as ptr) // 读取 C 字符串
偏移量以字节为单位;读写不会做边界检查,越界访问属于未定义行为(C 语义), 仅应在已知布局的 C 结构体/缓冲区上使用。read_str/read_bytes 返回的字符串 参与帧管理,函数返回时自动释放。
14. Map 字典函数(map)
Map[str, V] 的运行时操作通过 map. 命名空间调用(无需 import)。 编译器按 Map 变量的声明值类型(V)自动分派到底层实现,用户无需关心。 (Map 类型的声明、生命周期与所有权语义见语言基础语法文档第 13 章。)
| 函数 | 签名 | 描述 |
|---|
map.create | () -> int | 创建空 Map,返回句柄(等价于 {} 字面量) |
map.set | (Map, str, V) -> void | 写入键值(V 为 Map 声明的值类型;字符串值拷贝存储) |
map.get | (Map, str) -> V | 读取值;缺键返回默认值(int→0、float→0.0、str→空串) |
map.has | (Map, str) -> bool | 检查键是否存在 |
map.len | (Map) -> int | 返回键值对数量 |
map.delete | (Map, str) -> bool | 删除键,返回是否删除成功 |
map.keys | (Map) -> str | 返回所有键(换行分隔的帧管理字符串) |
map.clear | (Map) -> void | 清空所有键值对 |
map.free | (Map) -> void | 提前释放 Map(可省略,函数返回时帧自动释放) |
rexvar m: Map[str, int] = {}
map.set(m, "a", 1)
map.set(m, "b", 2)
if map.has(m, "a") {
print(map.get(m, "a")) // 1
}
print(map.len(m)) // 2
map.free(m)
值类型约束:Map[str, int] / Map[str, float] / Map[str, str] 三种组合可用; 使用 Map[int, ...](非字符串键)或其他值类型会得到编译错误。 缺键语义:map.get 对缺键返回默认值,需要区分"缺键"与"值为默认值"时先 map.has。 内存语义:见语言基础语法文档第 13 章「Map 字典」(帧生命周期 + 单所有者隐式移动 + 返回值自动移交)。
15. Set 集合函数(set)
Set[T] 的运行时操作通过 set. 命名空间调用(无需 import)。 编译器按 Set 变量的声明元素类型(T)自动分派到底层实现,用户无需关心。 所有操作均支持方法糖(s.add(x) ≡ set.add(s, x))。 (Set 类型的声明、生命周期与所有权语义见语言基础语法文档第 14 章。)
| 函数 | 签名 | 描述 |
|---|
set.create | () -> int | 创建空 Set,返回句柄 |
set.add | (Set, T) -> void | 添加元素(T 为 Set 声明的元素类型;重复添加不生效) |
set.remove | (Set, T) -> bool | 删除元素,返回是否原本存在 |
set.has | (Set, T) -> bool | 检查元素是否存在 |
set.len | (Set) -> int | 返回元素数量 |
set.clear | (Set) -> void | 清空所有元素 |
set.free | (Set) -> void | 提前释放 Set(可省略,函数返回时帧自动释放) |
rexvar s: Set[int] = set.create()
set.add(s, 10)
if set.has(s, 10) {
print(set.len(s)) // 1
}
set.free(s)
元素类型约束:Set[int] / Set[float] / Set[str] 三种组合可用; 其他元素类型会得到编译错误。 内存语义:见语言基础语法文档第 14 章「Set 集合」(帧生命周期 + 单所有者隐式移动 + 返回值自动移交)。
16. JSON、HTTP 与加密库(FFI 扩展库)
以下库是用户级 Rex 库(非编译器内置),通过 FFI 绑定成熟的 C 库/纯 C shim 实现:
lib/json.rex:绑定 cJSON(C 语言 JSON 库)lib/http.rex:绑定 libcurl(C 语言 HTTP 客户端库,Windows 上经 Schannel 原生 TLS 支持 https)lib/crypto.rex:绑定 crypto_helper.dll(纯 C 自实现的哈希/HMAC/AES/Base64/Hex,无外部依赖)
原生依赖(native/ 目录):cjson.dll、libcurl.dll、curl_helper.dll、crypto_helper.dll,由 gcc 编译。 使用前提(JIT 模式):当前工作目录包含 native/ 目录(DLL 通过相对路径 native/<库名> 加载)。
AOT 模式(rex build):三个库全部静态链接进 exe,无需任何 DLL—— cJSON 由 native/cJSON.c + native/json_helper.c、crypto 由 native/crypto_helper.c、 http 由 native/curl_helper.c + 静态 libcurl_static.a(Schannel TLS,支持 https) 提供;AOT exe 可独立分发。
16.1 导入方式
rex// 必须整模块导入!
// selective import(如 import json_parse from "lib/json.rex")会过滤掉 extern 声明,导致链接失败
import "lib/json.rex"
import "lib/http.rex"
16.2 JSON 库(lib/json.rex)
所有函数以 json_ 前缀命名。节点类型统一为 ptr。
| 分类 | 函数 | 说明 |
|---|
| 解析/释放 | json_parse(text: str) -> ptr | 解析 JSON,失败返回 null(用 json_error() 查原因) |
| json_free(node: ptr) | 释放整棵 JSON 树 |
| json_error() -> str | 最近一次解析出错的位置描述 |
| 序列化 | json_print(node: ptr) -> str | 格式化输出(带缩进) |
| json_print_min(node: ptr) -> str | 紧凑输出 |
| 类型判断 | json_is_object/array/string/number/bool/null/true/false(node: ptr) -> int | 类型检查 |
| json_type(node: ptr) -> int | 类型位掩码(json_type_object() 等常量函数) |
| 读取 | json_get(obj: ptr, key: str) -> ptr | 取对象键对应的子节点(不存在返回 null) |
| json_get_at(arr: ptr, index: int) -> ptr | 取数组元素(越界返回 null) |
| json_size(arr: ptr) -> int | 数组元素个数 |
| json_string(node: ptr) -> str | 字符串节点的值 |
| json_number(node: ptr) -> float | 数字节点的值 |
| json_bool_value(node: ptr) -> int | 布尔节点的值(1/0) |
| 遍历 | json_child(node: ptr) -> ptr / json_next(node: ptr) -> ptr | 遍历子节点链表 |
| json_key(node: ptr) -> str | 节点键名(对象成员名) |
| 构建 | json_obj()/json_arr()/json_str()/json_num()/json_bool()/json_null() -> ptr | 创建节点 |
| json_add_obj(obj, key, item) -> int / json_add_arr(arr, item) -> int | 挂载子节点(所有权转移给父节点) |
内存规则:
json_parse 返回的节点必须用 json_free 释放json_add_obj / json_add_arr 把 item 所有权转移给父节点,释放父节点时子节点一并释放json_print 等返回的 str 由 Rex 帧自动管理,无需手动释放
示例:
reximport "lib/json.rex"
fn main() {
// 解析
let root: ptr = json_parse("{\"name\": \"Rex\", \"age\": 30, \"tags\": [\"a\", \"b\"]}")
if root == null {
print("解析失败:", json_error())
return
}
print(json_string(json_get(root, "name"))) // Rex
print(json_number(json_get(root, "age")) as int) // 30
// 遍历数组
let tags: ptr = json_get(root, "tags")
for i in range(0, json_size(tags)) {
print(json_string(json_get_at(tags, i)))
}
// 构建
let obj: ptr = json_obj()
json_add_obj(obj, "id", json_num(1.0))
json_add_obj(obj, "ok", json_bool(1))
print(json_print_min(obj)) // {"id":1,"ok":true}
json_free(root)
json_free(obj)
}
16.3 HTTP 库(lib/http.rex)
所有函数以 http_ 前缀命名。请求失败时抛出异常(消息为 curl 错误描述),可用 try/catch 捕获。
| 函数 | 说明 |
|---|
http_get(url: str, timeout_ms: int) -> str | GET 请求,返回响应体 |
http_post(url: str, body: str, content_type: str, timeout_ms: int) -> str | POST 请求(content_type 可传 null) |
http_request(method: str, url: str, body: str, headers: str, timeout_ms: int) -> str | 通用请求;headers 为换行分隔的 "Key: Value"(可传 null) |
http_status() -> int | 最近一次请求的 HTTP 状态码 |
http_response_headers() -> str | 最近一次请求的原始响应头 |
http_error_str(code: int) -> str | curl 错误码转错误描述 |
注意事项:
timeout_ms <= 0 时使用默认 30000ms- 响应体/响应头/状态码是"最近一次请求"的快照,须在发起下一次请求前读取
- 自动跟随重定向(最多 10 次)、自动 gzip/deflate 解压、User-Agent 固定为
rex-http/1.0
示例:
reximport "lib/http.rex"
import "lib/json.rex"
fn main() {
// GET + JSON 解析
let body: str = http_get("https://httpbin.org/get", 10000)
let root: ptr = json_parse(body)
if root != null {
print(json_string(json_get(root, "url")))
json_free(root)
}
// POST JSON
let resp: str = http_post("https://httpbin.org/post",
"{\"hello\": \"world\"}",
"application/json", 10000)
print("status =", http_status())
// 错误处理
try {
http_get("http://127.0.0.1:9/", 2000)
} catch err {
print("请求失败:", err)
}
}
16.4 加密/编码库(lib/crypto.rex)
所有函数以 crypto_ 前缀命名。由 native/crypto_helper.c 纯 C 自实现(无 OpenSSL 等外部依赖),gcc 编译为 crypto_helper.dll。
| 分类 | 函数 | 说明 |
|---|
| 哈希摘要 | crypto_md5(text: str) -> str | MD5,返回小写 hex(32 字符) |
| crypto_sha1(text: str) -> str | SHA-1,返回小写 hex(40 字符) |
| crypto_sha256(text: str) -> str | SHA-256,返回小写 hex(64 字符) |
| crypto_sha512(text: str) -> str | SHA-512,返回小写 hex(128 字符) |
| HMAC | crypto_hmac_sha1(key: str, msg: str) -> str | HMAC-SHA1 摘要(hex) |
| crypto_hmac_sha256(key: str, msg: str) -> str | HMAC-SHA256 摘要(hex),常用于 API 签名 |
| crypto_hmac_sha512(key: str, msg: str) -> str | HMAC-SHA512 摘要(hex) |
| AES 加密 | crypto_aes_encrypt_ecb_128(key_hex, data) -> str | AES-128 ECB 加密,返回 Base64 密文 |
| crypto_aes_encrypt_ecb_256(key_hex, data) -> str | AES-256 ECB 加密 |
| crypto_aes_encrypt_cbc_128(key_hex, iv_hex, data) -> str | AES-128 CBC 加密 |
| crypto_aes_encrypt_cbc_256(key_hex, iv_hex, data) -> str | AES-256 CBC 加密 |
| AES 解密 | crypto_aes_decrypt_ecb_128(key_hex, b64) -> str | AES-128 ECB 解密(输入 Base64 密文) |
| crypto_aes_decrypt_ecb_256(key_hex, b64) -> str | AES-256 ECB 解密 |
| crypto_aes_decrypt_cbc_128(key_hex, iv_hex, b64) -> str | AES-128 CBC 解密 |
| crypto_aes_decrypt_cbc_256(key_hex, iv_hex, b64) -> str | AES-256 CBC 解密 |
| 编码 | crypto_base64_encode(data: str) -> str | Base64 编码 |
| crypto_base64_decode(b64: str) -> str | Base64 解码 |
| crypto_hex_encode(data: str) -> str | 十六进制编码(小写) |
| crypto_hex_decode(hex: str) -> str | 十六进制解码 |
约定与限制:
- 密钥/IV 以 hex 字符串传入:AES-128 密钥 = 32 个 hex 字符(16 字节);AES-256 密钥 = 64 个 hex 字符(32 字节);IV = 32 个 hex 字符(16 字节)
- 密文以 Base64 返回(AES 密文含不可打印字节,无法直接作为
str 传递);解密时传入 Base64 密文 - AES 使用 PKCS7 填充;解密成功时自动去填充
- 参数非法返回空字符串
""(密钥长度错误、密文损坏、hex 非法等),不抛异常 - 输入均为文本字符串,不支持内嵌
\0 的二进制数据(C 字符串语义) - 返回的
str 由 Rex 帧自动管理,无需手动释放(C 侧临时内存由 shim 内部释放) - 已实现并测试的算法均通过标准测试向量验证(RFC 1321/FIPS 180/RFC 2202,AES 与 pycryptodome 交叉验证)
示例:
reximport "lib/crypto.rex"
fn main() {
// 哈希摘要(API 签名常用)
print(crypto_sha256("hello")) // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
// HMAC 签名
print(crypto_hmac_sha256("secret", "message"))
// AES-256-CBC 加解密(密钥/IV 为 hex)
let key: str = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
let iv: str = "101112131415161718191a1b1c1d1e1f"
let cipher: str = crypto_aes_encrypt_cbc_256(key, iv, "Hello, Rex!")
print("密文:", cipher) // Base64
print("明文:", crypto_aes_decrypt_cbc_256(key, iv, cipher))
// Base64 / Hex 编码
print(crypto_base64_encode("Hello")) // SGVsbG8=
print(crypto_base64_decode("SGVsbG8=")) // Hello
print(crypto_hex_encode("AB")) // 4142
print(crypto_hex_decode("4142")) // AB
}
17. 完整代码示例
使用标准库命名空间
rex// 标准库函数内置,直接以命名空间调用,无需 import、无需 extern
fn main() {
let pi: float = math.pi()
print("π =", pi)
print("sin(π/2) =", math.sin(pi / 2.0))
print("cos(0) =", math.cos(0.0))
}
fn main() {
let path: str = "test.txt"
if file.exists(path) == 1 {
let content: str = file.read(path)
print("Content:", content)
}
}
fn main() {
random.seed(42)
for i in range(0, 5) {
print("Random:", random.int(100))
}
}