多个struct字段如何可以使用相同的更高生命期的泛型?

问题描述:

我的结构ReadingState采用函数recv_dgram作为其new()方法中的参数。 recv_dgram以一个生命期为'r的缓冲区作为参数,并返回某种类型的Future。未来的Item包含作为参数提供的缓冲区,具有相同的寿命'r多个struct字段如何可以使用相同的更高生命期的泛型?

这是怎么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和结果分配给外地的ReadingStateopt_read_future

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` 

A梦的解决方案(这不是有效的防锈代码)将是形式的东西:

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> <[[email protected]/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`. 

我不知道,我知道我在做什么,以及为什么改变编译问题。你可能有一个想法。

+0

你是说你希望'FUNC'的返回值与'F'相同吗?我不确定我是否可以跟随不幸的问题。你能把这个减少到一个简单的例子,可以预见在[playground](http://play.rust-lang.org/)中可以运行的东西吗? – Timidger

+0

注意:您可以使用[take](https://doc.rust-lang.org/std/option/enum.Option.html#method.take)来重新创建'Option'上的'mem :: replace' ) – Timidger

+0

@Timidger:我不知道'take'。这真的很酷,谢谢。 – real

从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略有不同,但如果您可以使类型一致,则可以将opt_read_future的类型更改为Option<FF::F<'c>>


作为一种变通方法,您可以使用Box<Future<...>>,而不是为Future类型的类型参数。

+0

我不知道PhantomData。我假设它用于为类型添加约束,非常有趣。我希望我不需要使用Box 解决方法,因为我想避免分配):我添加了独立代码示例,但它不能编译。 – real

+0

你不能有一个函数返回'MockFutureTrait ',因为这是一个未定义的类型。你需要返回一个实现'MockFutureTrait'的具体类型,但是你不能指定一个适用于*每个*生命周期的具体类型。 –

+0

我试图使用盒装的想法可以在[这个问题]上找到(https://*.com/questions/46253306/lifetime-problems-for-a-function-returning-a-boxed-trait-that-c​​ontains-一,参照的文) – real