如何手动返回Result <(),Box <Error >>?

rec*_*x51 5 error-handling type-systems rust

如果条件为真,我想从函数返回错误:

use std::error::Error;

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

    if condition {
        // return error
    }

    // -- snip --

    Ok(())
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

我可能没有类型系统的基础知识,但是在我所看到的所有地方,人们都在使用?运算符,所以我无法弄清楚要返回哪种类型。

  1. 是否可以仅返回这样的错误?
  2. 有没有更好的方法来处理这种逻辑?

jim*_*mis 10

我是 Rust 的新手,但这是我返回自定义错误的肮脏技巧,因为该函数设置为 return 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")?;
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • `return Err("错误请求".into());` (14认同)
  • `错误(“错误的请求”)?` (3认同)
  • 有人可以解释为什么附加“?”或使用“.into()”作为解决方案吗?其中一个比另一个更受青睐吗?@Stargateur @Shepmaster (3认同)
  • @Svilen `From&lt;&amp;str&gt;` 是为 `Box&lt;dyn Error&gt;` 实现的,并且 `.into()` 和 `?` 都使用该实现将字符串转换为错误框。(参见https://doc.rust-lang.org/std/boxed/struct.Box.html#impl-From%3C%26%27_%20str%3E-2) (3认同)
  • 作品!此外,我现在明白@Stargateur 的意思了,因为只写 `Err("Bad request")?`(没有 return 语句,末尾有问号)也有效!我认为这两种解决方案都更加优雅。我应该编辑答案吗? (2认同)

Fre*_*ios 8

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"
    }
}
Run Code Online (Sandbox Code Playgroud)

我建议您使用失败来删除所有错误样板:

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

-

请注意,如果期望使用an Error,则可以返回所需的任何类型,只要它实现即可Error。这包括中的错误类型std

  • 哇,太多了...现在我有更多问题... 1. 所以必须创建我自己的错误类型?是否不可能返回 std 中已定义的错误?2. 如果我使用您建议的编译器属性,代码会是什么样子?3.这个dyn是什么???它甚至没有列在《The Rust 编程语言》的附录 - A 中! (2认同)

小智 7

Box<dyn Error>对于实现它的类型来说很方便:

use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
   Err("March")?
}
Run Code Online (Sandbox Code Playgroud)

但令人惊讶的是,它并不适用于所有类型:

use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
   // the trait `std::error::Error` is not implemented for `{integer}`
   Err(9)?
}
Run Code Online (Sandbox Code Playgroud)

作为解决方法,您可以使用我所说的错误格式习惯用法:

use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
   Err(format!("{}", 9))?
}
Run Code Online (Sandbox Code Playgroud)

请注意,这有很多变体,例如,对于文字,您可以这样做:

use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
   Err(concat!(9))?
}
Run Code Online (Sandbox Code Playgroud)

而且,您甚至可能不需要使用Box<dyn Error>

fn main() -> Result<(), String> {
   Err(concat!(9))?
}
Run Code Online (Sandbox Code Playgroud)

在您通常不需要它的情况下它也很有用。例如,下面的示例可以在没有它的情况下工作,但它很有用,因为它将文件名添加到错误中,而该错误通常不会显示:

use std::fs;
fn main() -> Result<(), String> {
   let s = "a.rs";
   match fs::read_to_string(s) {
      Ok(v) => print!("{}", v),
      // normal message is just: The system cannot find the file specified
      Err(v) => Err(format!("{} {}", s, v))?
   }
   Ok(())
}
Run Code Online (Sandbox Code Playgroud)