Here's my test code:
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(())
}
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`
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: I'm pretty sure that you cannot in a generic way.
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
is only implemented for Box<T>
when T
is Sized
and implements Error
itself:
impl<T: Error> Error for Box<T> {
// ...
}
Said another way, Box<dyn Error>
does not implement Error
.
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
The best alternative I have to offer is to implement From
for each individual concrete type you need to support:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With