多个结构域如何成为使用相同的较高kinded生命周期的泛型?

时间:2017-09-13 16:32:55

标签: rust lifetime

我的结构ReadingState在其recv_dgram方法中将函数new()作为参数。 recv_dgram将带有生命周期'r的缓冲区作为参数,并返回某种类型的Future。此未来的Item包含作为参数提供的缓冲区,具有相同的生命周期'r

这就是ReadingState的样子:

struct FragMsgReceiver<'a, A, FUNC: 'a>
where
    FUNC: for<'r> FnMut(&'r [u8])
        -> Future<Item = (&'r [u8], usize, A), Error = io::Error>,
{
    frag_state_machine: FragStateMachine,
    recv_dgram: &'a mut FUNC,
    get_cur_instant: &'a mut FnMut() -> Instant,
}

struct ReadingState<'a, 'c, A, FUNC: 'a, F>
where
    F: Future<Item = (&'c mut [u8], usize, A), Error = io::Error>,
    FUNC: for<'r> FnMut(&'r [u8])
        -> Future<Item = (&'r [u8], usize, A), Error = io::Error>,
{
    frag_msg_receiver: FragMsgReceiver<'a, A, FUNC>,
    temp_buff: Vec<u8>,
    res_buff: &'c mut [u8],
    opt_read_future: Option<F>,
}

FUNC的返回类型与F不同,因为它们使用不同的生命周期。

结构本身可以编译,但我不能在我的其余代码中正确使用它们。例如,当我尝试拨打frag_msg_receiver.recv_dgram并将结果分配给opt_read_future的字段ReadingState时,会发生这种情况:

error[E0308]: match arms have incompatible types
  --> src/frag_msg_receiver.rs:80:30
   |
80 |               let mut fdgram = match mem::replace(&mut reading_state.opt_read_future, None) {
   |  ______________________________^
81 | |                 Some(read_future) => read_future,
82 | |                 None => (*reading_state.frag_msg_receiver.recv_dgram)(
83 | |                     &mut reading_state.temp_buff),
84 | |             };
   | |_____________^ expected type parameter, found trait frag_msg_receiver::futures::Future
   |
   = note: expected type `F`
              found type `frag_msg_receiver::futures::Future<Item=(&[u8], usize, A), Error=std::io::Error> + 'static`

一个梦想的解决方案(这不是有效的Rust代码)将是以下形式:

struct ReadingState<'a, 'c, A, FUNC: 'a, F> 
    where for <'r> {
        F: Future<Item = (&'r mut [u8], usize, A), Error = io::Error>,
        FUNC: FnMut(&'r [u8]) -> F,
    }
{
    // ...
}

我不知道如何使用现有语法实现这一目标。

编辑:我做了尽可能小的自包含示例,但它不会因为不同的原因而编译。我把它包括在这里(playground):

trait MockFutureTrait {
    type Item;
    fn get_item(self) -> Self::Item;
}

type FnTraitObject = FnMut(&mut [u8]) -> MockFutureTrait<Item=&mut [u8]>;

struct MockFuture<T> {
    item: T,
}

impl<T> MockFutureTrait for MockFuture<T> {
    type Item=T;
    fn get_item(self) -> Self::Item {
        self.item
    }
}

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

struct RecvMsg<'a,'c,F>
    where F: MockFutureTrait<Item=&'c mut [u8]> {

    frag_msg_receiver: FragMsgReceiver<'a>,
    res_buff: &'c mut [u8],
    read_future: F,
}


fn main() {
    let mut recv_dgram = |buf: &mut [u8]| {
        MockFuture {
            item: buf,
        }
    };

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

我得到的编译错误:

error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:33:26: 37:6] as std::ops::FnOnce<(&'r mut [u8],)>>::Output == MockFutureTrait<Item=&'r mut [u8]> + 'static`
  --> src/main.rs:40:21
   |
40 |         recv_dgram: &mut recv_dgram,
   |                     ^^^^^^^^^^^^^^^ expected struct `MockFuture`, found trait MockFutureTrait
   |
   = note: expected type `MockFuture<&mut [u8]>`
              found type `MockFutureTrait<Item=&mut [u8]> + 'static`
   = note: required for the cast to the object type `for<'r> std::ops::FnMut(&'r mut [u8]) -> MockFutureTrait<Item=&'r mut [u8]> + 'static + 'static`

error: aborting due to previous error

error: Could not compile `noncompiling_lifetime_trait`.

我不确定我知道自己在做什么,以及为什么编译问题会发生变化。你可能有个主意。

1 个答案:

答案 0 :(得分:1)

从Rust 1.20开始,你所希望做的事情是不可能的。您需要generic associated types才能在类型参数F上绑定正确的生命周期。解决方案看起来像这样(显然,我无法测试它,因为通用关联类型尚未实现):

use std::marker::PhantomData;

trait FragFutureFamily<A> {
    type F<'a>: Future<Item = (&'a [u8], usize, A), Error = io::Error>;
}

struct FragMsgReceiver<'a, A, FUNC: 'a, FF>
where
    FF: FragFutureFamily<A>,
    FUNC: for<'r> FnMut(&'r [u8]) -> FF::F<'r>,
{
    frag_state_machine: FragStateMachine,
    recv_dgram: &'a mut FUNC,
    get_cur_instant: &'a mut FnMut() -> Instant,
    _phantom_future_family: PhantomData<FF>,
}

struct ReadingState<'a, 'c, A, FUNC: 'a, F, FF>
where
    F: Future<Item = (&'c mut [u8], usize, A), Error = io::Error>,
    FF: FragFutureFamily<A>,
    FUNC: for<'r> FnMut(&'r [u8]) -> FF::F<'r>,
{
    frag_msg_receiver: FragMsgReceiver<'a, A, FUNC, FF>,
    temp_buff: Vec<u8>,
    res_buff: &'c mut [u8],
    opt_read_future: Option<F>,
    _phantom_future_family: PhantomData<FF>,
}

注意:我在F上保留了ReadingState类型参数,因为该类型与FragFutureFamily::F略有不同,但如果您可以使类型一致,则可以更改{的类型{1}}至opt_read_future

作为一种变通方法,您可以使用Option<FF::F<'c>>代替Box<Future<...>>类型的类型参数。