'Error in creating a function with a trait-bounded parameter wrapped in Option enum
I want to create a method for my MyError enum (whose variants are the different error types in my program) that returns a String value that describes the given MyError variant. For example:
pub enum MyError {
Error1,
Error2,
}
impl MyError {
pub fn to_str(&self) -> String {
match self {
Error1 => format!("Error1: bla bla bla"),
Error2 => format!("Error2: na na na"),
}
}
}
This is all well and good, but the problem is, I have a new error variant (say Error3) that must pass a parameter to its format!() macro in the method, like this:
Error3 => format!("la la la {:?}", arg),
This parameter can be of any type as long as it can derive the Debug trait. So my solution was
pub enum MyError {
Error1,
Error2,
Error3
}
impl MyError {
pub fn to_str(&self, arg: Option<&impl fmt::Debug>) -> String {
match self {
Error1 => format!("bla bla bla"),
Error2 => format!("na na na"),
Error3 => format!("la la la {:?}", arg),
}
}
}
Where I wrap the trait-bounded parameter in Option since some variants of MyError do not need it (e.g. Error1). This works for the Error3 variant, I can do the following without any compilation error:
eprintln!("{}", MyError::Error3.to_str(Some(vec![1, 2, 3])));
It prints the associated error message of Error3. But when I try to use the method to the other variants which require no additional parameter, e.g. calling
eprintln!("{}", MyError::Error1.to_str(None));
It returns the following compilation error:
type annotations needed
cannot infer type for type parameter `impl fmt::Debug` declared on the associated function `to_str`rustc(E0282)
Why can't the compiler infer the type of None here?
Solution 1:[1]
You need to specify the concrete type, even for None. Like this:
let n: Option<&Vec<usize>> = None;
eprintln!("{}", MyError::Error1.to_str(n));
Even though the function (method) only specifies a trait bound, not a concrete type, the compiler needs to know exactly the type of each value a caller passes to that function.
And of course, you can call the function with values of different type (but each of those needs to be clear and must adhere to the trait bound). An example:
pub fn main() {
let v1 = vec![1, 2, 3];
let v2 = "A str here";
eprintln!("{}", MyError::Error3.to_str(Some(&v1)));
eprintln!("{}", MyError::Error3.to_str(Some(&v2)));
let n: Option<&Vec<usize>> = None;
eprintln!("{}", MyError::Error1.to_str(n));
let n2: Option<&Vec<String>> = None;
eprintln!("{}", MyError::Error1.to_str(n2));
}
You can learn more here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
