Introducing closure trait leads to mismatch of life / concrete

I want to implement a trait for closures of a certain type. Here is a minimal example ( playground ):

trait Foo { fn foo(&self, x: &u32); } impl<F> Foo for F where F: Fn(&u32) { fn foo(&self, x: &u32) { self(x) } } fn main() { let _: &FnOnce(&u32) = &|x| {}; // works let _: &Foo = &|x| {}; // doesn't work } 

This results in an error:

 error: type mismatch resolving `for<'r> <[ closure@ <anon>:16:29: 16:35] as std::ops::FnOnce<(&'r u32,)>>::Output == ()`: expected bound lifetime parameter , found concrete lifetime [--explain E0271] --> <anon>:16:28 |> 16 |> let _: &Foo = &|x| {}; |> ^^^^^^^ note: required because of the requirements on the impl of `Foo` for `[ closure@ <anon>:16:29: 16:35]` note: required for the cast to the object type `Foo` error: type mismatch: the type `[ closure@ <anon>:16:29: 16:35]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r u32,)>` is required (expected concrete lifetime, found bound lifetime parameter ) [--explain E0281] --> <anon>:16:28 |> 16 |> let _: &Foo = &|x| {}; |> ^^^^^^^ note: required because of the requirements on the impl of `Foo` for `[ closure@ <anon>:16:29: 16:35]` note: required for the cast to the object type `Foo` 

I have already tried explicitly adding HRTB to the where clause as follows:

 where F: for<'a> Fn(&'a u32) 

But it did not help. I also declared the lifetime in the impl block, for example:

 impl<'a, F> Foo for F where F: Fn(&'a u32) { ... } 

But this leads to a lifetime error in the impl block. I think these errors are correct and the lifetime parameter cannot be declared in the impl block.

How can I fix this example?

+7
traits rust lifetime
source share
3 answers

Check this part of the error:

[...] implements the sign std::ops::Fn<(_,)> , but for<'r> std::ops::Fn<(&'r u32,)>

I think that basically there is not enough code for the types to be correctly inferred. Adding an explicit type annotation allows you to compile an example:

 let _: &Foo = &|x: &u32| {}; 
+4
source share

Here's a partial answer, starting with an interesting experiment:

 trait Foo { fn foo(&self, x: &u32); } impl<F> Foo for F where F: Fn(&u32) { fn foo(&self, x: &u32) { self(x) } } fn main() { let f1: &Fn(&u32) = &|_x| {}; let f2: &Foo = &f1; // but this fails: // let f3: &Foo = &|_x| {}; f2.foo(&3); } 

( Playground )

All I did was change FnOnce to Fn for consistency with the FnOnce and assign your first FnOnce closure to &Foo - and that works.

This tells me that the feature itself is beautiful β€” the problem is to determine the type of closure when creating the feature object. Returning to the error, we were told that the closure implements std::ops::Fn<(_,)> , but for<'r> std::ops::Fn<(&'r u32,)> . This means that the first thing you tried (adding for<'r>... to the trait) had no effect, because this trait already requires it.

I’m stuck at this point - I don’t think I understand enough of the withdrawal rules to close to understand why there is a difference or how it works. I hope someone comes and fills it!

+3
source share

Disclaimer: I have no idea what I'm doing.

The following works:

 trait Foo<'a> { fn foo(&self, x: &'a u32); } impl<'a, F> Foo<'a> for F where F: Fn(&'a u32) { fn foo(&self, x: &'a u32) { self(x) } } 
0
source share

All Articles