无法推断包含对闭包的引用的结构的生命周期

时间:2017-09-13 10:20:04

标签: rust lifetime

我正在努力使这个简化且自包含的代码版本编译:

struct FragMsgReceiver<'a, 'b: 'a> {
    recv_dgram: &'a mut FnMut(&mut [u8]) -> Result<&'b mut [u8], ()>,
}

impl<'a, 'b> FragMsgReceiver<'a, 'b> {
    fn new(
        recv_dgram: &'a mut FnMut(&mut [u8])
            -> Result<&'b mut [u8], ()>
    ) -> Self {
        FragMsgReceiver { recv_dgram }
    }
}

fn main() {
    let recv_dgram = |buff: &mut [u8]| Ok(buff);
    let fmr = FragMsgReceiver::new(&mut recv_dgram);
}

这是错误:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:15:43
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                                           ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:22...
  --> src/main.rs:15:22
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
  --> src/main.rs:15:43
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                                           ^^^^
note: but, the lifetime must be valid for the block suffix following statement 1 at 16:53...
  --> src/main.rs:16:53
   |
16 |       let fmr = FragMsgReceiver::new(&mut recv_dgram);
   |  _____________________________________________________^
17 | | }
   | |_^
note: ...so that variable is valid at time of its declaration
  --> src/main.rs:16:9
   |
16 |     let fmr = FragMsgReceiver::new(&mut recv_dgram);
   |         ^^^

根据我从错误消息中理解,编译器不理解buff引用(recv_dgram的参数)实际上可以比recv_dgram的内部主体更长寿。我可能错了。

为了给出一些上下文,我正在尝试创建一个包装Rust Tokio UDP套接字的结构。为此,我引用了一个函数recv_dgram。在我的原始代码中,此函数将缓冲区作为参数,并返回Future。当Future准备就绪时,缓冲区将被填充。 Future项还包含发送方的地址和写入缓冲区的字节数。

1 个答案:

答案 0 :(得分:1)

让我们首先在声明中恢复elided lifetime

struct FragMsgReceiver<'a, 'b: 'a> {
    recv_dgram: &'a mut for<'c> FnMut(&'c mut [u8]) -> Result<&'b mut [u8], ()>,
}

此声明表示FragMsgReceiver拥有对FnMut特征对象的可变引用,该对象对具有任何生命期'c的切片进行可变引用并返回生命周期为'b: 'a的参考。

这不是你需要的。您需要一个FnMut,它返回一个与输入参数的生命周期相同的生命周期的引用。这可以写成:

type FnTraitObject = FnMut(&mut [u8]) -> Result<&mut [u8], ()>;

struct FragMsgReceiver<'a> {
    recv_dgram: &'a mut FnTraitObject,
}

impl<'a> FragMsgReceiver<'a> {
    fn new(recv_dgram: &'a mut FnTraitObject) -> Self {
        FragMsgReceiver { recv_dgram }
    }
}

Lifetime elision在这里做了正确的事情,但是编译器仍然抱怨:&#34;期望的绑定生命周期参数,找到具体的生命周期&#34;,指向FragMsgReceiver::new(&mut recv_dgram)

此错误是由Rust类型推断的限制引起的。我们需要通过强制关闭类型pointed out by DK.

来协助推理
fn constrain_handler<F>(f: F) -> F
where
    F: FnMut(&mut [u8]) -> Result<&mut [u8], ()>,
{
    f
}

// ...

let mut recv_dgram = constrain_handler(|buff| Ok(buff));

Complete code on the playground

为了澄清,for<'c>表示'c可以是任何生命周期,生命周期是在呼叫站点确定的。例如,指向函数fn foo(_: &u32) -> &u32的指针的类型为for<'a> fn(&'a u32) -> &'a u32