Right pattern for moving items between vectors

I should prefix this with the fact that I am a rust noob and still trying to figure things out so if I am making a dumb-ass mistake I apologize for that from the start.

I have two structures each containing vector properties.

pub struct Hand {
    pub player_id   : String,
    pub cards       : Vec<Card>
}

and

pub struct Deck {
    pub cards: Vec<Card>
}

I have a method on the deck that removes a card from the deck and adds it to the hand

    pub fn deal(&self, hands: &mut Vec<Hand>, cards: &mut Vec<Card>, quantity: i8) {
        for _i in 1..=quantity {
              for hand in hands.iter() {
                  let card = cards.remove(0);
                  hand.cards.push(card);
            }
        }
    }

This does not work

cannot borrow `hand.cards` as mutable, as it is behind a `&` reference

I tried creating a function to simplify things a bit

fn add_card_to_hand(hand_collection: &mut Vec<Card>, card_collection: &mut Vec<Card>, index: usize) {
    let card = card_collection.remove(index);
    hand_collection.push(card);
}

and changed the deal function to

    pub fn deal(&self, hands: &Vec<Hand>, quantity: i8) {
        let mut cardCollection = &self.cards;

        for _i in 1..=quantity {
              for hand in hands.iter() {
                  let mut handCollection = &hand.cards;
                  add_card_to_hand(&mut handCollection, &mut cardCollection, 0);
            }
        }
    }

but now I get this error

error[E0596]: cannot borrow data in a `&` reference as mutable
  --> src\cards\deck.rs:63:36
   |
63 |                   add_card_to_hand(&mut handCollection, &mut cardCollection, 0);
   |                                    ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

So the question is this.
What is the right pattern that I should follow when I want to move an element from one vector to another vector that exists on different structures?

The whole can borrow can't borrow thing is confusing.
Is there a great tutorial video reference that can be reconmended.

You need to use iter_mut if you want a mutable reference to it in the loop.

2 Likes

In addition to iter_mut(), you have lots of & that need to be &mut. Any & along the path from the original owned data structure to the mutation operation prevents mutation.

High level advice: treat this as you would a type error. "Cannot borrow..." can be read as "need &mut T, found &T", since these are in fact two distinct types. As with any type error: add explicit type annotations to narrow down the problem. Figure out which operation returned the wrong type, and change it to the right operation.

3 Likes

The final working version

    pub fn deal(&mut self, hands: &mut Vec<Hand>, quantity: i8) {
        for _i in 1..=quantity {
              for hand in hands.iter_mut() {
                  let card = self.cards.remove(0);
                  hand.cards.push(card);
            }
        }
    }

Thank you for the help much appreciated!!
I will never forget iter_mut again :slight_smile:

  • i8 is an unusual choice of type for this purpose. Try u32.
  • _ rather than _i
  • 0..quantity rather than 1..=quantity
  • iter_mut is redundant. This is enough: for hand in hands {
  • Run rustfmt. (cargo fmt)
  • cards.remove(0) has linear time complexity, and repeatedly calling it is quadratic time complexity. Better remove items from the other end. Call Vec::pop instead of Vec::remove.
2 Likes

Or if the order is important, consider swapping to VecDeque::pop_front.

Or Vec::splice to remove all items in one go, unless there's a good reason to use VecDeque. But generally, if order is important, construct the collection in reverse order to be able to pop it from the back.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.