web-dev-qa-db-ja.com

結果<()、ボックス<dynエラー>>を手動で返す方法は?

条件が真の場合に関数からエラーを返したい:

use std::error::Error;

pub fn run() -> Result<(), Box<dyn Error>> {
    // -- snip ---

    if condition {
        // return error
    }

    // -- snip --

    Ok(())
}

fn main() {}

私はおそらくタイプシステムの基本を理解していませんが、私が見たところどこでも?演算子なので、どの型を返すのかわかりません。

  1. このようなエラーを返すことは可能ですか?
  2. このロジックを処理するより良い方法はありますか?
6
rect0x51

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"
    }
}

すべてのエラーボイラープレートを削除する failure を使用することをお勧めします。

#[derive(Fail, Debug)]
#[fail(display = "There is an error: {}.", _0)]
struct MyError(String);

-

Errorが実装されていれば、Errorが必要な場合は、任意の型を返すことができます。これには、stdのエラータイプが含まれます。

8

私は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")?;
    }
    // ...
}
2
jimis

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>に固執する必要はありませんが、必要なタイプを返すことができます。制限なしの汎用列挙型です。

?-演算子は 早期リターンの便利なショートカット なので、結果について冗長である必要はありません。

1
hellow