StarknetAstro

StarknetAstro

06_Cairo 中的Option(特殊Enum)

06_Cairo 中的 Option (特殊 Enum)#

与 Rust 一样,Cairo 同样没有 Null 这种代表空的系统级变量或者属性。因为这样很容易出现:将空值当作非空值,或者将非空值当作空值的错误。

为了更好的理解这个错误,举一个 Golang 的例子:

在使用 Golang 的 Map 的时候,经常会出现” 从一个状态为 nil 的 Map 中读取数据” 的错误,因为 Map 可能在运行时是一个 nil。nil 在 Golang 中就表示空值的意思。

在 Cairo 中就不会出现这类错误,因为 Cairo 编译器在编译的时候,就能够发现这类错误。实现这个效果的原因就是:Cairo 没有 Null 这种代表空的系统级变量或者属性,Cairo 使用一个特殊的 Enum 类型来实现非空判断 (Option)。

Option 的基本使用#

标准库中是这么定义 Option 的

enum Option<T> {
    Some: T,
    None: (),
}

在实际编码中时可以这么定义 Option 类型的变量:

use option::OptionTrait;

fn main(){
    let some_char = Option::Some('e');
    let some_number: Option<felt252> = Option::None(());
    let absent_number: Option<u32> = Option::Some(8_u32);
}

Option 的 Some 成员是泛型,所以可以装入任意类型,上面我们就将一个短字符串装入了 Some 里。另外需要注意的是,如果使用的是 None,参数不可以为空,需要传入单位类型 ()。单位类型是 Cairo 中的一个特殊类型,它是用来保证它所在的位置的代码不会被编译 (编译时的空状态)。

与 Rust 的异同#

与 Rust 相同点:

  • 使用 None 时,需要指定 Option 中的类型,就像上面的 let some_number: Option<felt252> = Option::None(());,因为编译器通过 None 无法判断 Option 里面装的是什么类型。

与 Rust 不同点:

  • None 和 Some 不可以直接全局使用。

不可以将其他类型的变量和 Option 一起混用#

use option::OptionTrait;

fn main() {
    let x: u8 = 5_u8;
    let y: Option<u8> = Option::Some(5_u8);

    let sum = x + y;
}

// 得到如下错误:
error: Unexpected argument type. Expected: "core::integer::u8", found: "core::option::Option::<core::integer::u8>".
 --> h04_enum_option.cairo:11:19
    let sum = x + y;
                  ^

虽然 Option 变量 y 中装的是一个 u8 的值,但是 y 和 x 的类型是不同的,所以不可以将两个相加。

Cairo 中的非空判断#

Cairo 中所有类型的变量都是非空的,编译器会保证变量在任何时刻都不为空,就像上面的 x 变量。也就是说,我们在编写 Cairo 代码时,无需担心:我是否忘记检查我的变量在运行中是一个空值。唯一需要考虑是否是空值的地方,就是使用 Option 变量的时候。

换句话说,只有 Option 才可以获取到空值的这个状态(None)。我们可以通过 match 的控制模式来看看 Option 的实际使用案例。

源码剖析#

Option 核心库的源码:https://github.com/starkware-libs/cairo/blob/main/corelib/src/option.cairo

4 个成员函数#

有 4 个成员函数:

/// 判断Option中是否有值,如果有返回这个值;如果没有,抛出 err 错误
fn expect(self: Option<T>, err: felt252) -> T;

/// 判断Option中是否有值,如果有返回这个值;如果没有,也会抛出错误,此错误不是自定义的错误
fn unwrap(self: Option<T>) -> T;

/// 如果Option有值,返回true
fn is_some(self: @Option<T>) -> bool;

/// 如果Option没有值,返回false
fn is_none(self: @Option<T>) -> bool;
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。