Reputation: 10025
I'm trying to implement a simple pattern: if I have some error I can try to recover my application, otherwise I just pop this exception to the caller:
use std::error::Error;
fn main() {
let _ = sample();
}
fn sample() -> std::result::Result<i32, std::io::Error> {
let result: Result<i32, std::io::Error> = Ok(10); // performing some operation
match result {
Ok(x) => Ok(x + 1),
Err(e) => match e.cause() {
// if it has any error
Some(cause) => {
// and it has any cause
let io_error = cause.downcast_ref::<std::io::Error>(); // and this cause is IO error
match io_error {
Some(_) => Ok(547), // return default value
None => Err(e), // otherwise return an error
}
}
None => Err(e),
},
}
}
I want to return x+1
if the operation succeeds. If it doesn't, but it's caused by an io::Error
then return 547
. If it's caused by something else, just return an error as-is.
The current compiler error is:
error[E0597]: `e` does not live long enough
--> src\main.rs:11:25
|
11 | Err(e) => match e.cause() { // if it's caused
| ^ borrowed value does not live long enough
...
21 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
I don't understand why it says that it must have the static
lifetime...
Upvotes: 1
Views: 927
Reputation: 299960
It's unfortunate, indeed, that the compiler is not more explicit.
Let me unwind this:
Error::downcast_ref
is only implemented for Error + 'static
(thus, when self
lifetime itself is 'static
),cause.downcast_ref
, cause
must be 'static
,Error::cause
ties down the lifetime of its result to that of self
,e.cause()
, e
must be 'static
,e
is a temporary introduced in Err(e)
.Hopefully, this is clearer.
I have not used it yet, however one of the Rust core team members (withoutboats) has been working on a new failure
crate which supposedly solves a number of issue with the Error
usage.
Upvotes: 3
Reputation: 431069
Because that's a requirement of the function you are using:
impl Error + 'static {
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T>
}
You cannot downcast trait objects that are not 'static
.
The example code can be reduced further to make this more clear. Commenting out the downcast_ref
allows the code to be compiled:
fn example(result: Result<i32, std::io::Error>) -> Result<i32, std::io::Error> {
let e = result.unwrap_err();
let cause = e.cause().unwrap();
let _io_error = cause.downcast_ref::<std::io::Error>();
unimplemented!()
}
This may just be an artifact of your reduced example code, but I don't understand why you are taking a Result<_, std::io::Error>
and checking to see if the cause of the io::Error
was another io::Error
. If your Result
was an Err
, then you know that was an io:Error
as it's the only possible thing. io::Error
doesn't even provide a cause, unless you are using a custom error variant.
See also:
Upvotes: 2