【问题标题】:How can I implement From for both concrete Error types and Box<Error> in Rust?如何在 Rust 中为具体的错误类型和 Box<Error> 实现 From?
【发布时间】:2019-03-12 13:24:00
【问题描述】:

这是我的测试代码:

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

struct Handler {
    error: String
}

#[derive(Debug)]
struct SpecificError;

impl fmt::Display for SpecificError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SpecificError")
    }
}

impl Error for SpecificError {}

impl<E: Error> From<E> for Handler {
    fn from(e: E) -> Self {
        Handler { error: format!("{}", e) }
    }
}

fn fail1() -> Result<(), SpecificError> {
    Err(SpecificError)
}

fn fail2() -> Result<(), Box<Error>> {
    Err(Box::new(SpecificError))
}

fn handler() -> Result<(), Handler> {
    fail1()?;
    fail2()?;
    Ok(())
}

fail1() 的调用很好,但对fail2() 的调用无法编译:

error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time
  --> src/main.rs:35:5
   |
35 |     fail2()?;
   |     ^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn std::error::Error`
   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::error::Error>`
   = note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::error::Error>>` for `Handler`
   = note: required by `std::convert::From::from`

我同意编译器dyn Error 在编译时没有已知大小,但我不明白为什么这是相关的,因为我尝试转换的类型是Box&lt;dyn Error&gt;,它确实有一个在编译时已知的大小。

【问题讨论】:

    标签: rust


    【解决方案1】:

    TL;DR:我很确定你不能以通用的方式。

    我不明白这有什么关系,因为我尝试转换的类型是 Box&lt;dyn Error&gt;,它的大小在编译时是已知的。

    这不是它抱怨的地方。再看报错信息(稍微清理一下):

    the trait `Sized` is not implemented for `dyn Error`
    required because of the requirements on the impl of `Error` for `Box<dyn Error>`
    required because of the requirements on the impl of `From<Box<dyn Error>>` for `Handler`
    required by `From::from`
    

    第二行是重要的。这是您的问题的更简单再现:

    use std::error::Error;
    
    fn example<E: Error>() {}
    
    fn main() {
        example::<Box<dyn Error>>();
    }
    
    error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time
     --> src/main.rs:6:5
      |
    6 |     example::<Box<dyn Error>>();
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
      |
      = help: the trait `std::marker::Sized` is not implemented for `dyn std::error::Error`
      = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
      = note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::error::Error>`
    note: required by `example`
     --> src/main.rs:3:1
      |
    3 | fn example<E: Error>() {}
      | ^^^^^^^^^^^^^^^^^^^^^^
    

    Error 只是 implemented for Box&lt;T&gt; when T is Sized 并实现 Error 本身:

    impl<T: Error> Error for Box<T> {
        // ...
    }
    

    换一种说法,Box&lt;dyn Error&gt; 不实现Error

    有人可能认为您可以为Box&lt;Error&gt; 添加第二个From 实现,但这是不允许的:

    upstream crates may add new impl of trait `std::error::Error` for type
    `std::boxed::Box<(dyn std::error::Error + 'static)>` in future versions
    

    我必须提供的最佳选择是为您需要支持的每个具体类型实现From

    impl From<SpecificError> for Handler {
        fn from(e: SpecificError) -> Self {
            Handler { error: format!("{}", e) }
        }
    }
    
    impl From<Box<dyn Error>> for Handler {
        fn from(e: Box<dyn Error>) -> Self {
            Handler { error: format!("{}", e) }
        }
    }
    

    宏可以减少这里的样板。

    【讨论】:

      猜你喜欢
      • 2020-03-31
      • 1970-01-01
      • 2020-10-08
      • 2023-02-08
      • 1970-01-01
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多