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;
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。