0

I want to use an API that I can modify reg:

struct Ctx;
trait Foo {}

trait Ex {
    fn do_<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a>;
}

impl<F> Ex for F
where
    F: for<'a> Fn(&'a mut Ctx) -> Box<Foo + 'a>,
{
    fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
        (*self)(ecx)
    }
}

fn reg<F>(name: &str, ext: F)
where
    F: Ex + 'static,
{
}

//My code starts here
struct Boo;

impl Boo {
    fn f1<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a> {
        unimplemented!();
    }
}

fn main() {
    let boo = Boo;
    reg("aaa", move |cx| boo.f1(cx));
}

But I got an error:

error[E0271]: type mismatch resolving `for<'a> <[closure@src/main.rs:33:16: 33:36 boo:_] as std::ops::FnOnce<(&'a mut Ctx,)>>::Output == std::boxed::Box<Foo + 'a>`
  --> src/main.rs:33:5
   |
33 |     reg("aaa", move |cx| boo.f1(cx));
   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
   |
   = note: concrete lifetime that was found is lifetime '_#9r
   = note: required because of the requirements on the impl of `Ex` for `[closure@src/main.rs:33:16: 33:36 boo:_]`
   = note: required by `reg`

error[E0281]: type mismatch: `[closure@src/main.rs:33:16: 33:36 boo:_]` implements the trait `std::ops::Fn<(&mut Ctx,)>`, but the trait `for<'a> std::ops::Fn<(&'a mut Ctx,)>` is required
  --> src/main.rs:33:5
   |
33 |     reg("aaa", move |cx| boo.f1(cx));
   |     ^^^        -------------------- implements `std::ops::Fn<(&mut Ctx,)>`
   |     |
   |     requires `for<'a> std::ops::Fn<(&'a mut Ctx,)>`
   |     expected concrete lifetime, found bound lifetime parameter 'a
   |
   = note: required because of the requirements on the impl of `Ex` for `[closure@src/main.rs:33:16: 33:36 boo:_]`
   = note: required by `reg`

How can I fix this?

In real code my struct Boo contains some data, and want to call reg for it twice, so I not implement trait Ex, but try to use closure.

user1244932
  • 7,352
  • 5
  • 46
  • 103
  • Have you read https://stackoverflow.com/q/31362206/155423; https://stackoverflow.com/q/41087239/155423; https://stackoverflow.com/q/24847331/155423; https://stackoverflow.com/q/24162518/155423; https://stackoverflow.com/q/40535543/155423? Those were the *first* 5 SO questions I found with the error text "concrete lifetime that was found". Please [edit] your question to explain how it's different from those. – Shepmaster Aug 29 '17 at 19:09
  • @Shepmaster Even if strip struct, variables, traits, functions names my code completly different from question you suggest. My question is little similar to **answer** from https://stackoverflow.com/questions/32194367/expected-bound-lifetime-parameter-found-concrete-lifetime , but actually code in solution cause problems. – user1244932 Aug 29 '17 at 19:58

1 Answers1

1

Looks like issue #38714.

While it is being fixed, you can directly implement Ex for Boo.

impl Ex for Boo {
    fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
        self.f1(ecx)
    }    
}

fn main() {
    let boo = Boo;
    reg("aaa", boo);
}

In real code my struct Boo contains some data, and want to call reg for it twice, so I not implement trait Ex, but try to use closure.

You'll not be able to do that with the code you provided. move |cx| boo.f1(cx) moves boo into the closure, and you can't use boo after that.

If you want to share data, you'll need to use Rc in Boo.

red75prime
  • 3,733
  • 1
  • 16
  • 22
  • Yes, in real code I use `Rc`, so move not a problem for me. While two time implement `Ex` one for `Boo`, one for `struct XXX(Boo)` is not good, so I try to use closure. – user1244932 Sep 01 '17 at 16:23