条件が真の場合に関数からエラーを返したい:
use std::error::Error;
pub fn run() -> Result<(), Box<dyn Error>> {
// -- snip ---
if condition {
// return error
}
// -- snip --
Ok(())
}
fn main() {}
私はおそらくタイプシステムの基本を理解していませんが、私が見たところどこでも?
演算子なので、どの型を返すのかわかりません。
Error
は特性であり、特性オブジェクトを返したい( dyn
キーワードに注意 )なので、この特性を実装する必要があります:
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct MyError(String);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "There is an error: {}", self.0)
}
}
impl Error for MyError {}
pub fn run() -> Result<(), Box<dyn Error>> {
let condition = true;
if condition {
return Result::Err(Box::new(MyError("Oops".into())));
}
Ok(())
}
fn main() {
if let Err(e) = run() {
println!("{}", e); // "There is an error: Oops"
}
}
Debug
、Display
、次にError
を実装し、Err
のResult
バリアントを返します。すべてのエラーボイラープレートを削除する failure を使用することをお勧めします。
#[derive(Fail, Debug)]
#[fail(display = "There is an error: {}.", _0)]
struct MyError(String);
-
Error
が実装されていれば、Error
が必要な場合は、任意の型を返すことができます。これには、std
のエラータイプが含まれます。
私はRustの初心者ですが、関数がResult<(), Box<dyn Error>>
を返すように設定されている場合、カスタムエラーを返すダーティなハックを次に示します。
fn serve(config: &Config, stream: TcpStream) -> Result<(), Box<dyn Error>> {
// ...
if request_is_bad() {
// This returns immediately a custom "Bad request" error
Err("Bad request")?;
}
// ...
}
Result<T, E>
は2つのバリアントを持つ列挙型です。それらのいずれかを返すには、対応するバリアントを使用するだけです。
fn foo(var: bool) -> Result<(), i32> {
if var {
Ok(()) //in fact this is std::result::Result::Ok
} else {
Err(-3) //in fact this is std::result::Result::Err
}
}
std::result::Result::Ok
を記述する必要がないのは、それが prelude にあるためです。ご覧のとおり、Box<Error>
に固執する必要はありませんが、必要なタイプを返すことができます。制限なしの汎用列挙型です。
?
-演算子は 早期リターンの便利なショートカット なので、結果について冗長である必要はありません。