錯誤處理
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::Warning 在 run() 的事件流中發出:
rust
let mut handle = instance.run(symbol, timeframe);
while let Some(result) = handle.next_event().await {
match result? {
Event::Warning(warnings) => {
eprintln!("{}", warnings.display());
}
_ => {}
}
}最佳實踐
- 始終處理編譯錯誤 — 向使用者顯示帶原始碼上下文的錯誤
- 也要處理
build()的異常 —build()執行全域範疇以發現腳本元資料(indicator()、input.*()等),因此頂層程式碼中的任何執行時錯誤(如runtime.error()、無效的函式參數)都會在執行開始之前以Error::Exception的形式出現 - 遇到執行時錯誤立即停止 — Navi 逐 K 線計算,每根 K 線的結果依賴前一根的狀態(
var變數、series 歷史參照如close[1]等)。如果某根 K 線計算出錯,後續所有結果都將無效,因此應立即終止 - 處理事件流中的事件 — 日誌事件可能包含有用的診斷資訊;消費
run()回傳的流或使用run_to_end()丟棄事件 - 建構後檢查警告 — 它們通常指示已棄用的功能或潛在的 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(())
}下一步
- LSP 與編輯器支援 — 語言伺服器功能