【问题标题】:Returning error message to function expecting 'Box<dyn Error>'将错误消息返回到期望“Box<dyn Error>”的函数
【发布时间】:2019-10-15 11:08:08
【问题描述】:

我是 Rust 新手,正在尝试传播要在调用函数中处理的错误。从官方的 rust book 中,我读到 Result 'Box' 用来表示捕获任何类型的错误,但我还没有读到足够多的内容来理解它的实际工作原理。

我有一个函数叫做:

fn foo() -> Result<String, Box<dyn Error>> {
    Command::new("an_executable")
        .args(&["-p", path])
        .output()?;
    if condition {
        return Err("Error...");
    }
    // Do stuff, return String 
}

如果某个返回类型满足条件,那么有人可以解释我应该如何返回错误。我是否必须更改返回类型或只是返回不同的东西。在这种情况下,RUST 标准是什么?

当前编译错误是 Err("Error...") 与返回类型不匹配

【问题讨论】:

  • 您是否尝试按照字面意思输入类型并返回Err(Box::new(...))?现在无法检查(我正在使用移动设备),但这可能有效。
  • @Cerberus 嗨,感谢您的关注。我尝试这样做: Box::new(Err("error")) 给出了预期的编译错误枚举std::result::Result,找到了结构std::boxed::Box 并且还尝试了你的示例:它给出了错误,特征绑定&amp;str: std::error::Error 是不满足 std::error::Error 的特征未针对 &amp;str 实现注意:强制转换为对象类型 dyn std::error::Errorrustc(E0277)

标签: error-handling rust


【解决方案1】:

让我们专注于您的问题的绝对最小重现:

use std::error::Error;

fn foo() -> Result<String, Box<dyn Error>> {
    Err("Error...")
}

这段代码返回的错误是:

error[E0308]: mismatched types
 --> src/lib.rs:4:9
  |
4 |     Err("Error...")
  |         ^^^^^^^^^^ expected struct `std::boxed::Box`, found reference
  |
  = note: expected type `std::boxed::Box<dyn std::error::Error>`
             found type `&'static str`

这是说函数签名希望您返回一个包含Box&lt;dyn Error&gt;Err,但实际上您返回了一个包含&amp;strErr。由于类型不对齐,编译器会抛出错误。

解决这个问题的最简单方法是使用Into trait,它实现了&amp;strBox&lt;dyn Error&gt; 之间的转换:

use std::error::Error;

fn foo() -> Result<String, Box<dyn Error>> {
    Err("Error...".into())
    // `Err(Box::from("Error..."))` would also work
}

工作原理

您可能仍然想知道 .into() 调用在幕后究竟做了什么。

首先,让我们看看如果我们只使用 Box&amp;str 会发生什么:

use std::error::Error;

fn foo() -> Result<String, Box<dyn Error>> {
    Err(Box::new("Error..."))
}
error[E0277]: the trait bound `&str: std::error::Error` is not satisfied
 --> src/lib.rs:4:9
  |
4 |     Err(Box::new("Error..."))
  |         ^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `&str`
  |
  = note: required for the cast to the object type `dyn std::error::Error`

同样,这不起作用,因为类型不对齐 - 它期望 Box 包含实现 Error 特征的东西,但如果你 look at the docs,你会注意到 @987654339 @ 不是实现它的类型之一。你需要将你的字符串包装成一个实现Error的类型:

use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct StrError<'a>(&'a str);

// Error doesn't require you to implement any methods, but
// your type must also implement Debug and Display.
impl<'a> Error for StrError<'a> {}

impl<'a> fmt::Display for StrError<'a>{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Delegate to the Display impl for `&str`:
        self.0.fmt(f)
    }
}

fn foo() -> Result<String, Box<dyn Error>> {
    Err(Box::new(StrError("Error...")))
}

这段代码可以编译,基本上就是 impl Into&lt;Box&lt;dyn Error&gt;&gt; for &amp;str 在幕后所做的 :)

【讨论】:

  • 谢谢,这解决了代码问题。我需要更多地阅读 RUST 以完全了解内部工作原理,但此修复按预期工作。非常感谢!
  • 感谢您的回答。我会把那个编辑放在你答案的开头,然后在下面留下解释..
  • @zertyz:完成:)
  • @JoeClay 如果您需要像使用 println {:?} 一样调用内部变量怎么办?
  • @Kaluk:您可以使用format! 宏生成String,使用与println! 相同的格式语法。然后String 可以像&amp;str 一样转换成Box&lt;dyn Error&gt;
猜你喜欢
  • 1970-01-01
  • 2020-03-26
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多