可恢復的錯誤是那些完全停止程式並不嚴重的錯誤。可以處理的錯誤稱為可恢復錯誤。
它由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)
},
};
}
執行上面範例程式碼,得到以下結果 -
程式說明
OK
和Err
變體之前使用Result::
。'f'
變數中。 在匹配之後,可以在檔案中執行讀取或寫入操作。Err
值起作用。 如果Result
返回Error
值,那麼panic!
執行並停止程式的執行。<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!
巨集顯示錯誤資訊。
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
。String
的OK
值,如果函式失敗,則返回Err
值。File::open
函式。 如果File::open
函式失敗,那麼匹配的第二個控制代碼將返回Err
值,如果File::open
函式成功,則它將檔案控制代碼的值儲存在變數f
中。File::open
函式成功,那麼建立一個String
的變數。 如果read_to_string()
方法成功,則返回檔案的文字,否則返回錯誤資訊。?
操作符使用?
運算子減少了程式碼的長度。?
運算子是匹配表示式的替換意味著?
運算子的工作方式與匹配表示式的工作方式相同。 假設有一個名為 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
值型別之前使用。 如果Result
為OK
,則返回OK
變體的值,如果Result
為Err
,則返回錯誤資訊。
?
運算子的錯誤通過’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")?;
}