lifetimes in structures that contain both a piece of data and the data being referenced are duplicates

I think I got it sorted out. Luckily everything builds just fine after pushing through a handful of errors.

Original Error

Ok. Here is the full error I saw when I tried to build your crate.

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/game.rs:42:31
   |
42 |                 player.add_card(self.deck.draw_white().unwrap())?;
   |                                           ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 39:2...
  --> src/game.rs:39:2
   |
39 |     pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/game.rs:42:21
   |
42 |                 player.add_card(self.deck.draw_white().unwrap())?;
   |                                 ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'c` as defined on the impl at 20:6...
  --> src/game.rs:20:6
   |
20 | impl<'c> Game<'c> {
   |      ^^
note: ...so that the types are compatible
  --> src/game.rs:42:12
   |
42 |                 player.add_card(self.deck.draw_white().unwrap())?;
   |                        ^^^^^^^^
   = note: expected `&mut Player<'_>`
              found `&mut Player<'c>`

It looks like the problem is actually with deal_hands(). Rather than allowing the lifetime of &self to be elided, you need to specify the lifetime as &'c mut self. (The mut is because you are mutating self.players.) I’m not totally sure why Rust doesn’t elide the lifetime of self to 'c, but that’s probably another topic.

Next Error

The next error I ran into was

error: captured variable cannot escape `FnMut` closure body                                          
   --> src/game.rs:106:17                                                                            
    |                                                                                                
106 |                     .map(|num| player.play_card_by_index(num as usize))                        
    |                              - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to a
 captured variable which escapes the closure body                                                    
    |                              |                                                                 
    |                              inferred to be a `FnMut` closure                                  
    |                                                                                                
    = note: `FnMut` closures only have access to their captured variables while they are executing...
    = note: ...therefore, they cannot allow references to captured variables to escape

For this one, the problem is actually not in the error message. You need to specify the lifetime of Card in the return value of .play_card_by_index() because otherwise it’s not clear that the reference to Card actually outlives the closure. This means you need to adjust .play_card_by_index() to return &'c Card' instead of &Card`.

Final Error

There was a trivial error in your .get_player_names(). You just need to use .iter() instead of .into_iter() because the former will not take ownership of self. Also, you probably want to .clone() the player names too for a similar reason.

Full Diff

Here’s the full diff

diff --git a/src/game.rs b/src/game.rs
index 573d09d..5ccbf6b 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -36,7 +36,7 @@ impl<'c> Game<'c> {
 
        /// Hands need to be filled on every turn, so this lets us fill everyones'
        /// hands at once.
-       pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
+       pub fn deal_hands(&'c mut self) -> Result<(), Box<dyn std::error::Error>> {
                for player in &mut self.players {
                        while player.hand.len() < player.max_hand_size {
                                player.add_card(self.deck.draw_white().unwrap())?;
@@ -124,7 +124,10 @@ impl<'c> Game<'c> {
        }
 
        pub fn get_player_names(&self) -> Vec<String> {
-               self.players.into_iter().map(|player| player.name).collect()
+               self.players
+                       .iter()
+                       .map(|player| player.name.clone())
+                       .collect()
        }
 }
 
diff --git a/src/player.rs b/src/player.rs
index 4bd6848..9f95373 100644
--- a/src/player.rs
+++ b/src/player.rs
@@ -46,7 +46,7 @@ impl<'c> Player<'c> {
 
        /// Used in the TUI, we can play a card by index and get the reference
        /// to the card we played
-       pub fn play_card_by_index(&mut self, index: usize) -> & Card {
+       pub fn play_card_by_index(&mut self, index: usize) -> &'c Card {
                self.hand.remove(index)
        }
 
@@ -56,7 +56,7 @@ impl<'c> Player<'c> {
        /// instead of making the card on the client and sending the full card info,
        /// we can just send the UUID[s] of the cards that were played with some
        /// data about the order they were played in.
-       pub fn play_card_by_uuid(&mut self, uuid: Uuid) -> Option<& Card> {
+       pub fn play_card_by_uuid(&mut self, uuid: Uuid) -> Option<&Card> {
                // TODO: Find a better way to do this
                let mut index_of_card: usize = self.hand.len() + 1;
                for (index, card) in self.hand.iter().enumerate() {

Good Luck!

This looks like a fun project. I hope you continue to build it in Rust!

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top