Cannot infer a lifetime for a closure returning a boxed trait that contains a reference

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-12 04:38:33

问题


I am trying to compile the following code (playground):

trait MockFutureTrait {
    type Item;
}

struct MockFuture<T> {
    item: T,
}

impl<T> MockFutureTrait for MockFuture<T> {
    type Item = T;
}

struct FragMsgReceiver<'a, 'c: 'a> {
    recv_dgram: &'a FnMut(&mut [u8])
        -> Box<MockFutureTrait<Item = &mut [u8]> + 'c>,
}

fn constrain_handler<F>(f: F) -> F
where
    F: FnMut(&mut [u8]) -> Box<MockFutureTrait<Item = &mut [u8]>>,
{
    f
}


fn main() {
    let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
        Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
    });

    let ref_recv_dgram = &mut recv_dgram;
    let fmr = FragMsgReceiver {
        recv_dgram: ref_recv_dgram,
    };
}

And I get the compile error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:28:37
   |
28 |         Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
   |                                     ^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 27:44...
  --> src/main.rs:27:44
   |
27 |       let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
   |  ____________________________________________^
28 | |         Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
29 | |     });
   | |_____^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
  --> src/main.rs:28:37
   |
28 |         Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
   |                                     ^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<MockFutureTrait<Item=&mut [u8]> + 'static>, found std::boxed::Box<MockFutureTrait<Item=&mut [u8]>>)
  --> src/main.rs:28:9
   |
28 |         Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I tried to add various lifetime hints, but I couldn't get this code to compile.

My previous related questions on SO about this:

  • Cannot infer a lifetime for a struct containing a reference to a closure: Solving the same problem, when the return value is a simple struct and not a trait.

  • How can multiple struct fields be generics that use the same higher-kinded lifetime?: About trying to solve this problem without Boxes. The answer suggests that for now I will have to use Box>.

Note that I am using the helper function constrain_handler according to a suggestion I got in question 2; it allows me to overcome a different compilation error.


回答1:


It appears that you've missed a key takeaway of your previous questions and their duplicates:

  • Lifetime annotation for closure argument
  • Cannot infer a lifetime for a struct containing a reference to a closure
  • How to declare a lifetime for a closure argument

By declaring a type on the closure argument, you stop performing type inference for the arguments. This causes a new implicit lifetime to be generated by the closure, one which does not match your requirements. Just don't declare the type at all.

Next, you need to state that your closure is going to take a reference to some bytes and return a boxed trait object that will return some bytes of the same lifetime and contains a reference of that same lifetime:

struct FragMsgReceiver<'a> {
    recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
        -> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}

See Why is Box<Iterator<Item = &Foo> + 'a> needed? for more details about the + 'a syntax.

Then update constrain_handler to match:

struct FragMsgReceiver<'a> {
    recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
        -> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}

fn constrain_handler<F>(f: F) -> F
where
    F: for<'b> FnMut(&'b mut [u8])
        -> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
    f
}

fn main() {
    let mut recv_dgram = constrain_handler(|buf| Box::new(MockFuture { item: buf }));

    let fmr = FragMsgReceiver {
        recv_dgram: &mut recv_dgram,
    };
}

The whole thing can be made simpler if you just take a generic closure directly:

struct FragMsgReceiver<R>
where
    R: for<'b> FnMut(&'b mut [u8])
        -> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
    recv_dgram: R,
}

fn main() {
    let fmr = FragMsgReceiver {
        recv_dgram: |buf| Box::new(MockFuture { item: buf }),
    };
}


来源:https://stackoverflow.com/questions/46253306/cannot-infer-a-lifetime-for-a-closure-returning-a-boxed-trait-that-contains-a-re

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!