I am new to Rust and am trying to propagate errors to be handled in the calling function. From the official rust book I read that Result 'Box< dyn Error>' is used to say capture any type of error but I haven't read far enough to understand how it actually works.
I have a function called:
fn foo() -> Result<String, Box<dyn Error>> {
Command::new("an_executable")
.args(&["-p", path])
.output()?;
if condition {
return Err("Error...");
}
// Do stuff, return String
}
So can someone explain how I should be returning an error if a condition is met with that return type. Do i have to change the return type or just return something different. what would the RUST standard be in this scenario?
The current compilation error is that Err("Error...") mismatched with the return type
Let's focus on the absolute minimum reproduction of your issue:
use std::error::Error;
fn foo() -> Result<String, Box<dyn Error>> {
Err("Error...")
}
The error returned by this code is:
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`
It's saying that the function signature expected you to return an Err
containing a Box<dyn Error>
, but you actually returned an Err
containing a &str
. Since the types don't line up, the compiler throws an error.
The easiest way to fix this is to use the Into
trait, which implements a conversion between &str
and Box<dyn Error>
:
use std::error::Error;
fn foo() -> Result<String, Box<dyn Error>> {
Err("Error...".into())
// `Err(Box::from("Error..."))` would also work
}
You may still be wondering what exactly that magic .into()
call is doing behind the scenes.
First, let's see what happens if we just Box
the &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`
Again, this doesn't work because the types don't line up - it's expecting the Box
to contain something that implements the Error
trait, but if you look at the docs, you'll notice that &str
is not one of the types that implements it. You need to wrap your string in a type that does implement 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...")))
}
This code compiles, and is basically exactly what impl Into<Box<dyn Error>> for &str
does under the hood :)
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