2017-09-16 8 views
0

Je suis en train de compiler le code suivant (playground):Ne peut pas déduire toute une vie pour une fermeture retournant un trait en boîte contenant une référence

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, 
    }; 
} 

Et j'obtiens l'erreur de compilation:

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]>> 
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

J'ai essayé d'ajouter divers indices de durée de vie, mais je n'ai pas pu compiler ce code.

Mes dernières questions connexes sur SO à ce sujet:

Notez que je suis en utilisant la fonction d'aide constrain_handler selon une suggestion que je suis arrivé en question 2; cela me permet de surmonter une erreur de compilation différente.

+0

Je ne ai jamais vu une réponse à [mon commentez votre question originale] (https://stackoverflow.com/questions/46194930/lifetime-problems-with-struct-containing-function-reference#comment79358569_46194930) à propos de la raison pour laquelle vous voulez que ce soit une référence à une fermeture de toute façon. – Shepmaster

+0

@shepmaster: Existe-t-il un autre moyen de le faire?Ce que je veux faire est de prendre un socket basé sur le datagramme, et l'emballe dans un nouveau type qui me permettra d'envoyer et de recevoir des datagrammes abstraits (Il n'y a pas de correspondance 1-1 entre ceux-ci et les datagrammes sous-jacents). Par conséquent, je prends une référence à la fonction 'recv_dgram'. – real

Répondre

1

Il semble que vous avez manqué une clé à emporter vos questions précédentes et leurs doublons:

En déclarant un type sur la fermeture argument, vous cesser d'effectuer l'inférence de type pour les arguments. Cela entraîne une nouvelle durée de vie implicite générée par la fermeture, qui ne correspond pas à vos besoins. Ne déclarez pas le type du tout.

Ensuite, vous devez indiquer que votre fermeture va prendre une référence à quelques octets et retourner un objet de trait boxed qui renverra quelques octets de la même durée de vie et contient une référence de cette même vie:

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

Voir Why is Box<Iterator<Item = &Foo> + 'a> needed? pour plus de détails sur la syntaxe + 'a.

ensuite mettre à jour constrain_handler pour correspondre:

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, 
    }; 
} 

si vous prenez juste une fermeture générique peut être fait cela tout simple directement:

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 }), 
    }; 
} 
+0

Y a-t-il une différence entre votre première définition de 'FragMsgReceiver' et la seconde (Où vous utilisez' R' dans la clause where)? – real

+0

@real yes - ce n'est plus une référence à un objet trait (note manquante '& 'a') mais un type générique qui sera monomorphisé. – Shepmaster

+0

Je ne savais pas que c'était possible. Alors maintenant, la taille de FragMsgReceiver dépend de la taille de la fermeture? L'ensemble de la fermeture est-il stocké dans FragMsgReceiver? – real