天天看點

Rust語言從入門到精通系列 - 避免Panic程式崩潰

作者:TinyZzh
Rust語言從入門到精通系列 - 避免Panic程式崩潰

在Rust語言中,當發生一些不可修複的錯誤時,程式會崩潰并停止運作。這種崩潰被稱為"panic",其中包含了出現問題的檔案名和行号等資訊。

Panic是一種緊急情況,并且它們應該盡可能地被避免。盡管它們可能是不可避免的,但是在編寫代碼時我們應該嘗試處理盡可能多的錯誤。

如何使用Panic?

在Rust中,可以使用panic!宏來引發panic。此時,程式将停止運作并列印出錯誤資訊,這些資訊通常包括出錯的檔案名稱和行号等資訊。同時,也可以使用環境變量來擷取更多的棧跟蹤資訊。

struct Animal {
    name: String,
    age: u8,
}

impl Animal {
    fn new(name: String, age: u8) -> Animal {
        if age < 1 {
            panic!("Age cannot be less than 1.");
        }
        Animal { name, age }
    }
}

fn main() {
    let animal = Animal::new(String::from("Tom"), 0);
    println!("The animal's name is {} and age is {}.", animal.name, animal.age);
}           

在上述的示例代碼中,我們定義了一個結構體Animal,并為它添加了一個函數new,該函數接受一個名稱和一定年齡的參數。接着在new 函數中,我們加入了一行代碼,以檢查年齡是否小于1,如果小于1,則觸發panic。最後在main函數中,我們建立了一個名為animal 的執行個體,并輸出其名稱和年齡。但是由于我們傳遞的年齡小于1,是以當運作到這裡時,程式就會發生panic。

當運作這段代碼時,輸出如下資訊:

thread 'main' panicked at 'Age cannot be less than 1.', src/main.rs:9:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace           

這個資訊告訴我們,在執行new函數時,程式崩潰,并指出出錯的源代碼檔案和行号。同時,它還為我們建議了一個環境變量,以擷取更詳細的棧跟蹤資訊。

如何避免Panic?

對于大多數情況而言,應該盡可能少使用panic。在開始一個新的項目時,首先要考慮的是如何處理錯誤而不是如何處理成功的情況。

Result類型

在Rust中,可以使用Result類型來避免panic。Result類型包括兩個枚舉值:Ok和Err。當一個函數傳回Result 類型時,它要麼傳回一個包含成功結果資料的Ok,要麼傳回一個包含錯誤資訊的Err。這樣,調用者就可以選擇如何處理錯誤。

struct Animal {
    name: String,
    age: u8,
}

impl Animal {
    fn new(name: String, age: u8) -> Result<Animal, String> {
        if age < 1 {
            return Err(String::from("Age cannot be less than 1."));
        }
        Ok(Animal { name, age })
    }
}

fn main() {
    let animal_result = Animal::new(String::from("Tom"), 0);
    match animal_result {
        Ok(animal) => {
            println!("The animal's name is {} and age is {}.", animal.name, animal.age);
        }
        Err(error) => {
            println!("{}", error);
        }
    }
}           

在上面的代碼中,我們對new函數進行了修改,使其傳回Result類型。如果年齡小于1,則傳回一個包含錯誤資訊的Err 。如果年齡大于等于1,則傳回一個包含動物執行個體的Ok。

在main函數中,我們建立了一個名為animal_result的變量,并将其設定為調用Animal結構體中的new 函數的傳回值。我們使用match表達式來處理animal_result,如果成功,則輸出動物執行個體的名稱和年齡,否則則輸出錯誤資訊。

unwrap和expect方法

在Rust中的Result類型中,還有兩個用于從Ok值中提取值的方法:unwrap和expect 。這兩個方法都可以用于快速編寫測試代碼,并且在這種情況下,panic可能是可以接受的。但是在實際生産代碼中,應該避免使用這兩個方法,因為它們會利用panic而不是正确處理錯誤。

fn main() {
    let animal = Animal::new(String::from("Tom"), 1).unwrap();
    println!("The animal's name is {} and age is {}.", animal.name, animal.age);

    let animal = Animal::new(String::from("Tom"), 0).expect("Failed to create animal instance.");
    println!("The animal's name is {} and age is {}.", animal.name, animal.age);
}           

在上述示例中,我們在建立animal執行個體時使用了unwrap和expect方法。在使用unwrap方法時,如果傳回值是Ok,則傳回Ok 類型的值,否則觸發panic。而使用expect方法時,同樣是如果傳回值是Ok,則傳回Ok類型的值,并輸出指定的錯誤資訊,否則觸發panic。

總結

Rust語言的panic是一種程式崩潰的情況,應該盡可能地避免它的發生。為了避免panic,我們應該盡量使用Result 類型,并且在傳回錯誤時傳回一個包含錯誤資訊的Err。在測試代碼中,可以使用unwrap和expect方法,但是在實際生産代碼中應該避免它們的使用。