使用指南

错误处理

校验了什么、在哪一层校验、四个错误分类各是什么,以及为什么核心层坚持不 panic。

适合:开发者

x-iztro 把外部输入的校验放在尽量靠内的一层,三种编程语言共用同一道防线。 各语言只把错误翻译成自己的惯例类型,不重复校验、也不各自解释。

错误分类

每个错误都带一个机器可读的分类,跨语言取值相同 —— 判断用它,不要解析文案

分类含义
invalid_date日期格式非法、该日期不存在,或超出支持范围(公历 1583–9999)
invalid_time_index时辰索引越界(合法值 0–12)
invalid_argument其余入参或配置非法:未知的性别、盘面语言、星耀标识、开关取值、覆盖表长度错
internal库内部缺陷或运行时故障,不是调用方的错,请上报

各语言的错误类型

IztroError 枚举,code() 给出分类:

match by_solar(date, ti, Gender::Female, true, Language::ZhCN, Config::default()) {
    Ok(chart) => { /* ... */ }
    Err(e) => println!("{:20} {}", e.code(), e),
}
invalid_date         invalid solar date '2000-2-30': day is out of range for that month
invalid_date         invalid solar date '1000-1-1': year must be within 1583-9999
invalid_time_index   time_index must be 0-12, got 13

变体有三个:InvalidDateInvalidTimeIndexInternal。 枚举标了 #[non_exhaustive]match 时请留 _ 分支。

C FFI 与 wasm 出口把同一个错误落成 {"error":"<message>","code":"<code>"}, 由 serde 生成以保证转义完备。

校验范围与消息样例

消息一律小写起首、以冒号引出细节,并带上原始输入 —— 批量处理时能直接定位是哪一条数据出的问题。

输入消息样例
公历日期格式invalid solar date 'not-a-date': year is not a number
公历日期不存在invalid solar date '2000-2-30': day is out of range for that month
公历年份范围invalid solar date '1000-1-1': year must be within 1583-9999
农历月份invalid lunar date '2000-13-1': month must be within 1-12
农历该月天数invalid lunar date '2000-2-31': day is out of range for that lunar month
时辰索引time_index must be 0-12, got 13
性别invalid gender 'x': expected 'male' or 'female'
盘面语言invalid language 'fr-FR': expected one of zh-CN, zh-TW, en-US, ja-JP, ko-KR, vi-VN
自定义四化表长度invalid mutagens for 'gengHeavenly': expected 4 stars (lu, quan, ke, ji), got 3
自定义表收到译名invalid mutagens for 'gengHeavenly': unknown star '太阳'

在哪一层校验

日期与时辰在核心层校验,三种编程语言完全一致。 性别、盘面语言、配置开关、星耀标识这些以字符串传入的东西, 在绑定层解析时校验 —— Rust 侧它们本来就是枚举,不存在非法取值。

查不到不是错误

需要计算的入口返回错误;查询方法查不到时返回空值而非错误—— 「这张盘上没有这颗星」是正常结果,不是异常。

场景返回
某颗星不在这张盘上None / nil
宫位索引越界None / nil
该星没有亮度表None / 空串
反查一个不存在的译名None / 空串

拼错的标识会静默失效

chart.palace("soulPalce") 不会报错,只会返回空;has(["ziweiMj"]) 恒返回 False。 判断用枚举或常量(Python 的 PalaceName.SOUL、Go 的 iztro.PalaceSoul)—— 拼错时是编译期或构造期报错,不是运行期静默。 要校验一个外来的字符串,把它喂给枚举构造:PalaceName("x") 会抛 ValueError

为什么核心层不 panic

这不是风格偏好,是 wasm 目标带来的硬约束。

wasm 上 panic 会变成 trap,直接中止调用
catch_unwind 在 wasm 上无效——绑定层兜不住
每次 trap 都会永久损耗模块实例的栈空间,累积之后连合法调用都会失败

因此防线必须设在更靠内的一层:所有外部输入在进入算法前校验完毕,入口返回 Result。 绑定层的 catch_unwind 只负责兜底库内部的缺陷,不承担参数校验职责。

仍然 panic 意味着什么

排盘入口不会因非法外部输入而 panic。若真的遇到,那是库内部缺陷, 会以 internal 分类返回,应作为 bug 上报——而不是调用方需要防御的情况。

批量处理的写法

坏数据跳过、好数据继续,而不是整批失败:

let (charts, failed): (Vec<_>, Vec<_>) = rows
    .iter()
    .map(|r| by_solar(&r.date, r.ti, r.gender, true, Language::ZhCN, Config::default()))
    .partition(Result::is_ok);

逐条 API 的错误行为见 RustPythonGo 三页。

本页目录