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’ 的檔,它包含文本“zaixian” 。想要創建一個程式來讀取檔,先參考下麵一個簡單的例子:

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’ 的外部檔,並包含文本“zaixian” 。 因此,該程式讀取檔‘a.text’ 並顯示檔的內容。

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

使用?運算符減少了代碼的長度。?運算符是匹配運算式的替換意味著?運算符的工作方式與匹配運算式的工作方式相同。 假設有一個名為 a.txt 的檔,它包含文本 - “zaixian”。想要創建一個程式來對該檔執行讀取操作。

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

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")?;
}

上一篇: Rust不可恢復的錯誤 下一篇: Rust泛型