我如何为具体的错误类型和 Box<Error> 实现 From在锈? [英] How can I implement From for both concrete Error types and Box&lt;Error&gt; in Rust?

查看:34
本文介绍了我如何为具体的错误类型和 Box<Error> 实现 From在锈?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的测试代码:

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() 的调用不能编译:

The call to fail1() is fine, but the call to fail2() doesn't compile:

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,它的大小在编译时是已知的.

I agree with the compiler that dyn Error doesn't have a size known at compile time, but I don't understand why that's relevant, since the type I'm attempting to convert from is a Box<dyn Error>, which does have a size known at compile time.

推荐答案

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

TL;DR: I'm pretty sure that you cannot in a generic way.

我不明白为什么这是相关的,因为我试图从中转换的类型是 Box,它的大小在编译时是已知的.

I don't understand why that's relevant, since the type I'm attempting to convert from is a Box<dyn Error>, which does have a size known at compile time.

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

That's not the place it's complaining about. Look at the error message again (slightly cleaned up):

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`

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

The second line is the important one. Here's a simpler reproduction of your problem:

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 只是 TSized 时为 Box 实现并实现 Error本身:

Error is only implemented for Box<T> when T is Sized and implements Error itself:

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

换种说法,Box 没有实现Error.

Said another way, Box<dyn Error> does not implement Error.

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

One might think that you can add a second implementation of From for Box<Error>, but this is disallowed:

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

宏可以减少这里的样板.

A macro can reduce the boilerplate here.

这篇关于我如何为具体的错误类型和 Box<Error> 实现 From在锈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆