I’m following this YouTube guide on structuring a Rust project. I created an error.rs file where I keep my custom errors and it looks like this:
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// For starter, to remove as code matures.
#[error("Generic error: {0}")]
Generic(String),
}
After that I re-export the error in my prelude.rs
// Re-export the crate Error.
pub use crate::error::Error;
// Alias Result to be the crate Result.
pub type Result<T> = core::result::Result<T, Error>;
// Generic Wrapper tuple struct for newtype pattern,
// mostly for external type to type From/TryFrom conversions
pub struct W<T>(pub T);
And create a function that would use the error:
fn foo(n: i32) -> Result<i32> {
if n == 3 {
return Error::Generic("I don'l like 3".to_string());
}
Ok(n)
}
But when I try to use my custom error, Rust won’t allow it, saying that I need to wrap it in an Err value. Why can’t I use my own error when returning the Result, and is there a way I can avoid wrapping it in this situation?
error[E0308]: mismatched types
--> src/lib.rs:12:16
|
10 | fn foo(n: i32) -> Result<i32> {
| ----------- expected `std::result::Result<i32, error::Error>` because of return type
11 | if n == 3 {
12 | return Error::Generic("I don'l like 3".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<i32, Error>`, found `Error`
|
= note: expected enum `std::result::Result<i32, error::Error>`
found enum `error::Error`
help: try wrapping the expression in `Err`
|
12 | return Err(Error::Generic("I don'l like 3".to_string()));
| ++++ +
Just as a clarification, the youtuber got around this with the following code:
use crate::prelude::*;
use std::fs::DirEntry;
impl TryFrom<W<&DirEntry>> for String {
type Error = Error;
fn try_from(val: W<&DirEntry>) -> Result<String> {
val.0
.path()
.to_str()
.map(String::from)
.ok_or_else(|| Error::Generic(f!("Invalid path {:?}", val.0)))
}
}
>Solution :
Because your return type is Result not Error, they are different types. You have to return one of it’s variants Result::Ok or Result::Err.
pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E> where F: FnOnce() -> E, { match self { Some(v) => Ok(v), None => Err(err()), } }
as you can see takes a closure that returns the error type E, not a Result. And it wraps the returned value in Err, so code using it doesn’t have to wrap it.