Skip to content

错误处理

navi_vm::Error 枚举涵盖了编译时和运行时的错误。

错误类型

rust
pub enum Error {
    Compile(CompileErrors),          // 解析、类型检查或编译错误
    Exception(RuntimeError),         // 运行时异常(如 runtime.error())
    MissingScriptType,               // 没有 indicator()/strategy()/library() 调用
    InputValueNotFound(usize),       // with_input_value 中的无效输入 ID
    SetInputValue(usize, String),    // 输入值类型不匹配
    UnsupportedTimeFrame(TimeFrame), // 脚本不支持此时间周期
    SessionNotAllowed(TradeSession), // 交易时段类型未启用
    DataProvider(String),            // DataProvider 返回的错误
    LibraryScriptNotExecutable,      // 尝试执行库
}

处理错误

模式匹配

rust
async fn run(source: &str) {
    let mut instance = match Instance::builder(source, TimeFrame::days(1), "NASDAQ:AAPL")
        .build().await
    {
        Ok(inst) => inst,
        Err(Error::Compile(errors)) => {
            // 带源码位置显示编译错误(彩色)
            eprintln!("{}", errors.display());
            return;
        }
        Err(Error::MissingScriptType) => {
            eprintln!("Script must call indicator(), strategy(), or library()");
            return;
        }
        Err(Error::Exception(exception)) => {
            // 全局作用域运行时错误(如顶层代码中的 runtime.error())
            eprintln!("{}", exception.display());
            return;
        }
        Err(e) => {
            eprintln!("Build error: {}", e);
            return;
        }
    };

    // 运行
    match instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await {
        Ok(()) => {}
        Err(Error::Exception(exception)) => {
            eprintln!("Runtime exception: {}", exception.display());
        }
        Err(e) => {
            eprintln!("Execution error: {}", e);
        }
    }
}

编译错误

编译错误包含源码 span,用于精确的错误报告:

rust
match Instance::builder(source, tf, "NASDAQ:AAPL").build().await {
    Err(Error::Compile(errors)) => {
        // 使用 codespan-reporting 渲染所有诊断(彩色)
        eprintln!("{}", errors.display());

        // 或纯文本(无 ANSI 颜色)
        eprintln!("{}", errors.display().set_colorize(false));

        // 访问单个诊断
        for diag in errors.diagnostics() {
            eprintln!("  {}", diag.message);
        }
    }
    _ => {}
}

运行时异常

运行时异常发生在脚本执行期间(如 runtime.error() 调用、索引越界):

rust
match instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await {
    Err(Error::Exception(exception)) => {
        // 显示带源文件上下文和调用栈的异常
        eprintln!("{}", exception.display());

        // 直接访问错误 span
        if let Some(span) = exception.spans.first() {
            eprintln!("  at line {}", span.start.line);
        }
    }
    _ => {}
}

编译警告

警告不会阻止执行,但指示潜在问题。 Instance::warnings() 返回一个 Warnings 值,已包含源文件, 可以直接渲染:

rust
let instance = Instance::builder(source, tf, "NASDAQ:AAPL").build().await?;

let warnings = instance.warnings();
if !warnings.is_empty() {
    // 使用 codespan-reporting 渲染为黄色警告
    eprintln!("{}", warnings.display());
}

警告也会作为 Event::Warningrun() 的事件流中发出:

rust
let mut handle = instance.run(symbol, timeframe);
while let Some(result) = handle.next_event().await {
    match result? {
        Event::Warning(warnings) => {
            eprintln!("{}", warnings.display());
        }
        _ => {}
    }
}

最佳实践

  1. 始终处理编译错误 — 向用户显示带源码上下文的错误
  2. 也要处理 build() 的异常build() 执行全局作用域以发现脚本元数据(indicator()input.*() 等),因此顶层代码中的任何运行时错误(如 runtime.error()、无效的函数参数)都会在执行开始之前以 Error::Exception 的形式出现
  3. 遇到运行时错误立即停止 — Navi 逐 K 线计算,每根 K 线的结果依赖前一根的状态(var 变量、series 历史引用如 close[1] 等)。如果某根 K 线计算出错,后续所有结果都将无效,因此应立即终止
  4. 处理事件流中的事件 — 日志事件可能包含有用的诊断信息;消费 run() 返回的流或使用 run_to_end() 丢弃事件
  5. 构建后检查警告 — 它们通常指示已弃用的功能或潜在的 bug
rust

async fn run_safely(
    instance: &mut Instance,
    symbol: &str,
    timeframe: TimeFrame,
) -> Result<(), Error> {
    let warnings = instance.warnings();
    if !warnings.is_empty() {
        eprintln!("{}", warnings.display());
    }

    let mut handle = instance.run(symbol, timeframe);
    while let Some(result) = handle.next_event().await {
        match result? {
            Event::Log(log) => {
                eprintln!("[{:?}] {}", log.level, log.message);
            }
            Event::Alert(alert) => {
                println!("Alert: {}", alert.message);
            }
            _ => {}
        }
    }
    Ok(())
}

下一步

基于 MIT 许可证发布。