軌道
/
Cairo
Cairo
/
課程大綱
/
錯誤處理
錯誤

錯誤處理 在 Cairo

1 個練習

關於 錯誤處理

Cairo 提供了錯誤處理的技巧,用來解決問題、管理錯誤,讓程式碼在執行時能順利運行。

Cairo 中的錯誤有兩種:

  • 無法復原的錯誤:panic,這類錯誤會立刻終止程式。
  • 可復原的錯誤:Result,這類錯誤可以在執行時期處理。

無法復原的錯誤:panic

在 Cairo 中,程式執行時可能會出現意料之外的問題,導致所謂的「panic」執行時期錯誤。這會停止程式的執行,而在繼續執行毫無意義的情況下,這麼做很有幫助。panic 可能是不小心發生的,例如程式的動作導致 panic(像是存取超出陣列邊界的元素);也可能是刻意呼叫panic函式所造成的。

fn main() {
    let data = array![1, 2];

    if true {
        panic(data);
    }
    println!("This line will not be reached.");
}

執行這個範例會在主控台印出以下內容:

Run panicked with [1, 2, ].

另外還有一個特別的巨集 panic!,它允許使用ByteArray作為錯誤訊息。

panic!("The error for the panic! Error message is not limited to 31 characters anymore");

assert! 巨集

assert! 巨集是強制檢查程式碼中特定條件的實用工具。如果assert!裡的條件評估為false,程式就會帶著ByteArray錯誤訊息 panic。這通常用來在開發期間驗證假設,並確保值符合特定條件。

例如:

fn main() {
    let x = 5;
    assert!(x > 0, "x must be greater than zero");
}

如果x不大於零,程式就會以"x must be greater than zero"這則訊息 panic。assert!有助於檢查不變性與前置條件,不必手動撰寫錯誤處理程式碼。

nopanic 標記

Cairo 的nopanic標記表示某個函式永遠不會 panic。

fn function_never_panic() -> felt252 nopanic {
    108
}

標記為nopanic的函式,只能從同樣標記為nopanic的函式中呼叫。

panic_with 屬性

panic_with是 Cairo 的一個屬性,用來標記會回傳Option或Result的函式,並會為你標記的函式建立一個包裝函式;當該函式回傳Option::None或Result::Err時,這個包裝函式就會 panic。

#[panic_with('value is 0', wrap_not_zero)]
fn check_not_zero(value: u128) -> Option<u128> {
    if value == 0 {
        Option::None
    } else {
        Option::Some(value)
    }
}

fn main() {
    check_not_zero(0); // -> returns Option::None
    wrap_not_zero(0);  // -> panics with 'value is 0'
}

可復原的錯誤:Result

Result列舉能優雅地處理錯誤,提供回饋,而不是讓程式崩潰或產生未定義的行為。

enum Result<T, E> {
    Ok: T,
    Err: E,
}

我們來看個例子,看看如何用這個列舉來處理除以零的情況:

fn divide(a: u32, b: u32) -> Result<u32, ByteArray> {
    if b == 0 {
        return Result::Err("Error: Division by zero"); // Return an error if division by zero is attempted
    }
    Result::Ok(a / b)
}

fn main() {
    // Test with division by zero
    match divide(10, 0) {
        Result::Ok(result) => println!("Division successful: {}", result),
        Result::Err(e) => println!("{}", e),
    }
}

? 運算子

?運算子用於簡潔且隱式的錯誤處理,讓呼叫端的函式自行處理可能發生的錯誤。當你對Result或Option型別使用?運算子時,它會進行以下處理:

  • 如果值是Result::Ok(x)或Option::Some(x),它會直接回傳內部的值x。
  • 如果值是Result::Err(e)或Option::None,它會立刻從函式回傳,把錯誤或None往外傳遞。
fn parse_u8(s: felt252) -> Result<u8, felt252> {
    match s.try_into() {
        Option::Some(value) => Result::Ok(value),
        Option::None => Result::Err('Invalid integer'),
    }
}

fn do_something_with_parse_u8(input: felt252) -> Result<u8, felt252> {
    let input_to_u8: u8 = parse_u8(input)?;
    // DO SOMETHING
    let res = input_to_u8 - 1;
    Result::Ok(res)
}

fn main() {
    let number: felt252 = 258;
    match do_something_with_parse_u8(number) {
        Result::Ok(value) => println!("Result: {}", value),
        Result::Err(e) => println!("Error: {}", e),
    }
}
透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 錯誤處理

練習已鎖定

再解鎖 1 個練習,就能練習 錯誤處理