06_Cairo1.0 中的Option(特殊Enum)

153 阅读4分钟

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核心库的源码:github.com/starkware-l…

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;

实践经验

Option 类型是一种表示可选值的类型。它可以表示一个值存在(用 Some 表示,包含一个具体值),或者表示值不存在(用 None 表示)。在编程中,我们通常会遇到这种情况,即一个值在某些情况下存在,而在其他情况下不存在。

在 Cairo 代码中,Option 类型非常常见,因为它具有多种用途:

  1. 初始值:在某些情况下,可能无法立即为变量分配一个合适的初始值。Option 类型可以用来表示这种“待定”的初始值。
  2. 部分函数的返回值:部分函数是指在其整个输入范围内未定义的函数。在这种情况下,可以使用 Option 类型来表示函数可能无法为给定输入返回一个有效值的情况。
  3. 简单错误报告的返回值:对于一些可能会出错的函数,可以使用 Option 类型作为返回值。如果函数执行成功,则返回 Some,包含一个有效结果;如果出错,则返回 None
  4. 可选的结构体字段:结构体中的某些字段可能有时需要一个值,有时不需要。这时可以使用 Option 类型作为字段的类型,以便在需要时表示字段的存在或不存在。
  5. 可选的函数参数:在某些情况下,函数可能允许用户提供可选参数。如果用户提供了这个参数,函数可以使用 Some 作为参数值;如果用户未提供,则使用 None 表示参数未传递。

总之,Option 类型是一种灵活的方式,可以在许多场景下表示值的存在或不存在。这对于处理不确定性、错误处理以及实现更灵活的函数和数据结构非常有用。