错误

错误处理 属于 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属性

Cairo 的panic_with属性用来标记返回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 个练习即可练习 错误处理