Search code examples
rustclosureslifetimeinference

Lifetime inference for container objects inside closures


I have a routine that plays with objects in a container and references to those objects stored in another 2 containers.
However, I am not finding the rust way of doing this, the lifetime inference seems to forbid this and I don't know how to resolve it

fn main() {
    let mut deck : Deck = Deck::new();
    let mut p1 : Hand = Hand::new();
    let mut p2 : Hand = Hand::new();


    do_hands(|data: &[Card]| -> Result<(),()> {
      for card in data {
        deck.insert(card.id, CardCell::new(*card));

        let card: &CardCell = deck.get_mut(&card.id).unwrap();
        handle_hand(&mut card, &mut p1, &mut p2);

      }      
      return Ok(());
    });

}

Here is the full playground link: https://play.rust-lang.org/?gist=6079ade83e3fcf06f35397eac2e82d05&version=nightly


Solution

  • I played with the example in the playground and managed to get the code to compile, with the following changes:

    1. Change the signature of handle_hand

      The initial signature was fn handle_hand<'a>(_card: &'a mut CardCell, _p1: &mut Hand<'a>, _p2: &mut Hand<'a>), but this was what the compiler error is about. This signature requires all input to handle_hand to have the same lifetime, but that is not the case in your code. There, inside the closure, card clearly has a shorted lifetime than p1 and p2. So the revised signature simply becomes: fn handle_hand<'a, 'b>(_card: &'b mut CardCell, _p1: &mut Hand<'a>, _p2: &mut Hand<'a>).

    2. Change the signature of card inside the closure.

      Since handle_hand requires a &mut CardCell, you must then declare card as let mut card: &mut CardCell =...

    3. Derive the copy trait into the Card struct. I put this last since this may need to be changed depending on how you'd further write the struct. But at this point, it's just a wrapper of u64, and you can simply do #[derive(Clone, Copy] on it. This is required because the Cell struct you are using requires a Copy type. Derive works here because all your struct's fields already implement the Copy type.

    Here's the updated playground.