How to use a closure instead of a trait?
I want to register Gen::my_g
as a callback. The easy way is to implement trait Foo
for Gen
, but I don't want to implement trait Foo
for Gen
.
In other words, I want to comment out the code marked as B!!!
and uncomment the code marked as A!!!
.
This is not my code; I cannot change this:
struct S1;
struct TT;
trait MyRes {}
trait Foo {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a>;
}
impl<F> Foo for F
where
F: for<'a> Fn(&'a mut S1, &[TT]) -> Box<MyRes + 'a>,
{
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
(*self)(ecx, tt)
}
}
fn f1<F>(name: &str, extension: F)
where
F: Foo + 'static,
{
}
This is my code:
struct Gen {}
impl Gen {
fn register(self) {
// f1("aaa", move |ecx, tt| self.my_g(ecx, tt));//A!!!
f1("aaa", self); //B!!!
}
fn my_g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
unimplemented!();
}
}
impl Foo for Gen {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
self.my_g(ecx, tt)
}
}
If I uncomment //A!!!
, the compiler tells me what I don't understand:
error[E0271]: type mismatch resolving `for<'a, 'r> <[closure@src/main.rs:29:19: 29:52 self:_] as std::ops::FnOnce<(&'a mut S1, &'r [TT])>>::Output == std::boxed::Box<MyRes + 'a>` --> src/main.rs:29:9 | 29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!! | ^^ expected bound lifetime parameter, found concrete lifetime | = note: concrete lifetime that was found is lifetime '_#12r = note: required because of the requirements on the impl of `Foo` for `[closure@src/main.rs:29:19: 29:52 self:_]` = note: required by `f1` error[E0281]: type mismatch: `[closure@src/main.rs:29:19: 29:52 self:_]` implements the trait `std::ops::Fn<(&mut S1, &[TT])>`, but the trait `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>` is required --> src/main.rs:29:9 | 29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!! | ^^ --------------------------------- implements `std::ops::Fn<(&mut S1, &[TT])>` | | | requires `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>` | expected concrete lifetime, found bound lifetime parameter | = note: required because of the requirements on the impl of `Foo` for `[closure@src/main.rs:29:19: 29:52 self:_]` = note: required by `f1`
This is a known issue:
- Error type input error due to strange assumed type for closing argument
The Rust compiler is currently unable to infer that closures are valid for any lifetime (which is what the type requires Foo::g
). It will invoke any particular lifetime, but does not generalize it further.