Reputation: 255
I learned an idiom to give an alias to trait. But, when I applied this idiom to my code, I encountered a puzzling error.
Here is a simplified version of the code:
// `StrToStr` is an alias for `Fn(&str) -> &str`
trait StrToStr: Fn(&str) -> &str {}
impl<T> StrToStr for T where T: Fn(&str) -> &str {}
// A function that returns `StrToStr`
fn identity() -> impl StrToStr {
|s: &str| s
}
When I compile this code, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:77:18
|
77 | fn identity() -> impl StrToStr {
| ^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected reference `&str`
found reference `&str`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `rust-calc` due to previous error
After trying several times with different return types, this error seems to occur when returning a reference type. However, I do not know why this error occurs and how to avoid it.
I would appreciate your advice.
Upvotes: 5
Views: 835
Reputation: 255
I have found a work-around for this problem in a GitHub discussion. First, we define a no-op function to help in the type inference of the closure.
fn generalize_lifetime<F>(f: F) -> F
where
F: Fn(&str) -> &str,
{
f
}
Then, wrap the closure with generalize_lifetime
and the compilation will pass.
// `StrToStr` is an alias for `Fn(&str) -> &str`
trait StrToStr: Fn(&str) -> &str {}
impl<F> StrToStr for F where F: Fn(&str) -> &str {}
// A function that returns `StrToStr`
fn identity() -> impl StrToStr {
generalize_lifetime(|s| s)
}
Upvotes: 2