Rust可恢復的錯誤


可恢復的錯誤是那些完全停止程式並不嚴重的錯誤。可以處理的錯誤稱為可恢復錯誤。
它由Result <T,E>表示。 結果<T,E>是列舉,由兩個變體組成,即OK <T>Err <E>,它描述了可能的錯誤。

OK <T>:’T’是一種值,它在成功情況下時返回OK變數,這是一個預期的結果。
Err <E>:’E’是一種錯誤,它在失敗情況下時返回ERR變數,這是意想不到的結果。

Enum Result<T,E>  
{  
    OK<T>,  
    Err<E>,  
}
  • 在上面的例子中,Result是列舉型別,OK <T>&Err <E>是列舉型別的變體,其中'T''E'是泛型型別引數。
  • 'T'是一種值,它將在成功的情況下返回,而'E'是一種錯誤,它將在失敗的情況下返回。
  • Result包含泛型型別引數,因此在成功和失敗值可能不同的許多不同情況下使用標準庫中定義的結果型別和函式。

下面來看一個返回Result值的簡單範例:

use std::fs::File;  
 fn main()   
{  
     let f:u32 = File::open("vector.txt");  
}

執行上面範例程式碼,得到以下結果 -

在上面的範例中,Rust編譯器顯示該型別不匹配。 'f'u32型別,而File::open返回Result <T,E>型別。 上面的輸出顯示成功值的型別是std::fs::File,錯誤值的型別是std::io::Error

注意:

  • File::open返回型別是成功值或失敗值。 如果File::open成功,則返回檔案控制代碼,如果File::open失敗,則返回錯誤值。 結果列舉提供此資訊。
  • 如果File::open成功,則f將具有包含檔案控制代碼的OK變體,如果File::open失敗,則f將具有包含與錯誤相關的資訊的Err變體。

匹配表示式以處理結果變體

下面來看看一個匹配表示式的簡單範例:

use std::fs::File;  
fn main()  
{  
   let f = File::open("vector.txt");  
   match f   
   {  
       Ok(file) => file,  
       Err(error) => {  
       panic!("There was a problem opening the file: {:?}", error)  
     },  
   }; 
}

執行上面範例程式碼,得到以下結果 -

程式說明

  • 在上面的範例中,可以直接存取列舉變體,而無需在OKErr變體之前使用Result::
  • 如果結果正常,則返回檔案並將其儲存在'f'變數中。 在匹配之後,可以在檔案中執行讀取或寫入操作。
  • 匹配對Err值起作用。 如果Result返回Error值,那麼panic!執行並停止程式的執行。

出錯時 Error:unwrap()

  • 結果<T,E>有許多方法可以提供各種任務。 其中一種方法是unwrap()方法。 unwrap()方法是匹配表示式的快捷方法。 unwrap()方法和匹配表示式的工作方式是一樣的。
  • 如果Result值是OK變數,則unwrap()方法返回OK變數的值。
  • 如果Result值是Err變數,那麼unwrap()方法會呼叫panic!巨集。

下面來看一個簡單的範例:

use std::fs::File;  

fn main()  
{  
     File::open("hello.txt").unwrap();  
}

執行上面範例程式碼,得到以下結果:

在上面的例子中,unwrap()方法會自動呼叫panic!巨集顯示錯誤資訊。

Error: expect()

  • expect()方法的行為方式與unwrap()方法相同,即兩種方法都會引起panic!巨集顯示錯誤資訊。
  • expect()unwrap()方法之間的區別在於,錯誤訊息作為引數傳遞給expect()方法,而unwrap()方法不包含任何引數。 因此,可以說expect()方法可以跟蹤panic!的來源更容易。

下面看看一個簡單範例 -

use std::fs::File;  
fn main()  
{  
     File::open("hello.txt").expect("Not able to find the file hello.txt");  
}

執行上面範例程式碼,得到以下結果 -

在上面的輸出中,錯誤訊息顯示在程式中指定的輸出螢幕上,即「無法找到檔案hello.txt」,這會更容易找到錯誤程式碼的位置。 如果包含多個unwrap()方法,那麼很難找到unwrap()方法引發panic!顯示所有錯誤訊息。

傳播錯誤

傳播錯誤是一種將錯誤從一個函式轉發到另一個函式的機制。 錯誤傳播到呼叫函式,其中有更多資訊可用,以便可以處理錯誤。 假設有一個名為‘a.txt’ 的檔案,它包含文字「yiibai」 。想要建立一個程式來讀取檔案,先參考下面一個簡單的例子:

use std::io;  
use std::io::Read;  
use std::fs::File;  
fn main()  
{  
  let a = read_username_from_file();  
  print!("{:?}",a);  
}  
fn read_username_from_file() -> Result<String, io::Error>   
{  
    let f = File::open("a.txt");  
    let mut f = match f {  
    Ok(file) => file,  
    Err(e) => return Err(e),  
    };  
    let mut s = String::new();  
    match f.read_to_string(&mut s) {  
        Ok(_) => Ok(s),  
        Err(e) => Err(e),  
    }  
}

程式說明 -

  • read_username_from_file()函式返回Result <T,E>型別的值,其中'T'String型別,'E'io型別:Error
  • 如果函式成功,則返回一個包含StringOK值,如果函式失敗,則返回Err值。
  • 函式中首先呼叫File::open函式。 如果File::open函式失敗,那麼匹配的第二個控制代碼將返回Err值,如果File::open函式成功,則它將檔案控制代碼的值儲存在變數f中。
  • 如果File::open函式成功,那麼建立一個String的變數。 如果read_to_string()方法成功,則返回檔案的文字,否則返回錯誤資訊。
  • 假設我們有一個名為‘a.text’ 的外部檔案,並包含文字「yiibai」 。 因此,該程式讀取檔案‘a.text’ 並顯示檔案的內容。

傳播錯誤的捷徑:?操作符

使用?運算子減少了程式碼的長度。?運算子是匹配表示式的替換意味著?運算子的工作方式與匹配表示式的工作方式相同。 假設有一個名為 a.txt 的檔案,它包含文字 - 「yiibai」。想要建立一個程式來對該檔案執行讀取操作。

看看下面一個簡單的例子。

use std::io;  
use std::io::Read;  
use std::fs::File;  
fn main()  
{  
  let a = read_username_from_file();  
  print!("{:?}",a);  
}  
fn read_username_from_file() -> Result<String, io::Error>   
{  
   let mut f = File::open("a.txt")?;  
   let mut s = String::new();  
   f.read_to_string(&mut s)?;  
  Ok(s)  
}

在上面的例子中,?運算子是在Result值型別之前使用。 如果ResultOK,則返回OK變體的值,如果ResultErr,則返回錯誤資訊。

?運算子和匹配表示式的區別

  • 使用?運算子的錯誤通過’from’函式移動,’from’函式在標準庫中的from trait中定義。
  • ?運算子呼叫’from’函式,然後此函式將錯誤型別轉換為當前函式的返回型別中定義的錯誤型別。
  • 如果沒有錯誤發生,那麼?運算子任何函式末尾的運算子返回OK的值,如果發生錯誤,則返回Err的值。
  • 它使函式的實現更簡單。

鏈方法在 ?運算子之後呼叫

甚至可以通過在?運算子之後使用連結方法呼叫來縮短程式的程式碼。

下面來看一個簡單的例子:

use std::io;  
use std::io::Read;  
use std::fs::File;  
fn main()  
{  
  let a = read_username_from_file();  
  print!("{:?}",a);  
}  
fn read_username_from_file() -> Result<String, io::Error>   
{  
    let mut s = String::new();  
   File::open("a.txt")?.read_to_string(&mut s)?;  
   Ok(s)  
}

程式說明

在上面的例子中,將read_to_string()的呼叫連結到File::open("a.txt")?的呼叫結果。如果兩個函式(即read_to_string()File::open("a.txt")成功,則返回OK值,否則返回錯誤值。

?運算子的限制

?運算子只能在返回Result型別值的函式中使用。 ?運算子與匹配表示式的工作方式類似。 匹配表示式僅適用於Result返回型別。

下面通過一個簡單的例子來理解這一點。

use std::fs::File;  
fn main()   
{  
    let f = File::open("a.txt")?;  
}