How to work with vectors in the functional paradigm

In response to user input, I need to extend a vector in a vector of a struct, however I am having trouble doing this without mutating any of the vectors.

use std::iter;

type PlayerID = u32;

struct Player {
    money: u32, 
    id: PlayerID
}

struct Game {
    rounds: Vec<Vec<Bet>>,
    pot: u32
}
impl Game {
    fn new() -> Game {
        Game {
            pot: 0,
            rounds: Vec::new()
        }
    }
}

#[derive(Clone)]
struct Bet {
    amount: u32,
    player_id: PlayerID,
}

fn bet(game: Game, player: Player, amount: u32) -> (Game, Player) {
    assert!(player.money >= amount);
    
    let last_round: &Vec<Bet> = game.rounds
        .iter()
        .last()
        .expect("Badly initialized game.");
    let last_bet = match last_round.iter().last() {
        Some(bet) => bet.amount,
        None => 0
    };
    assert!(amount >= last_bet);
    
    let new_bet = Bet { player_id: player.id, amount };
    let mut last_round: Vec<Bet> = last_round.clone();
    last_round.extend(iter::once(new_bet));
    
    let mut new_rounds = game.rounds.clone();
    new_rounds[new_rounds.len() - 1] = last_round;
    
    (
        Game {
            rounds: new_rounds,
            pot: game.pot + amount,
            ..game
        }, 
        Player {
            money: player.money - amount,
            ..player
        }
    )
} 

fn main () {
    let player = Player {
        money: 100, 
        id: 0
    };
    let game = Game::new();
    bet(game, player, 10);
}

I tried to implement to implement the replacement of the last round by with iterators, but I failed to manage.

...
    let last_round: Vec<Bet> = last_round.iter().chain(iter::once(new_bet)).collect(); 

but then I am given the error

error[E0271]: type mismatch resolving `<std::iter::Once<Bet> as IntoIterator>::Item == &Bet`
  --> main.rs:45:50
   |
45 |     let last_round: Vec<Bet> = last_round.iter().chain(iter::once(new_bet)).collect(); 
   |                                                  ^^^^^ expected struct `Bet`, found `&Bet`

and when I try to do the replacement of the rounds it gives me a similar error.

error[E0271]: type mismatch resolving `<std::iter::Once<Vec<Bet>> as IntoIterator>::Item == &Vec<Bet>`
  --> main.rs:52:10
   |
52 |         .chain(iter::once(last_round))
   |          ^^^^^ expected struct `Vec`, found `&Vec<Bet>`
   |
   = note:   expected type `Vec<Bet>`
           found reference `&Vec<Bet>`
error[E0599]: the method `collect` exists for struct `std::iter::Chain<std::iter::Take<std::slice::Iter<'_, Vec<Bet>>>, std::iter::Once<Vec<Bet>>>`, but its trait bounds were not satisfied
  --> main.rs:53:10
   |
53 |           .collect();
   |            ^^^^^^^ method cannot be called on `std::iter::Chain<std::iter::Take<std::slice::Iter<'_, Vec<Bet>>>, std::iter::Once<Vec<Bet>>>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<std::iter::Once<Vec<Bet>> as Iterator>::Item = &Vec<Bet>`
           which is required by `std::iter::Chain<std::iter::Take<std::slice::Iter<'_, Vec<Bet>>>, std::iter::Once<Vec<Bet>>>: Iterator`
           `std::iter::Chain<std::iter::Take<std::slice::Iter<'_, Vec<Bet>>>, std::iter::Once<Vec<Bet>>>: Iterator`
           which is required by `&mut std::iter::Chain<std::iter::Take<std::slice::Iter<'_, Vec<Bet>>>, std::iter::Once<Vec<Bet>>>: Iterator`

The convention for collection iterators is as follows. For a collection type C<T>:

  • <C as IntoIterator>::into_iter() returns an iterator over the owned elements (consuming the collection).
  • <&C as IntoIterator>::into_iter() and the identically-behaved .iter() convenience function return an iterator over borrowed elements, borrowing the collection immutably.
  • <&mut C as IntoIterator>::into_iter() and the identically-behaved .iter_mut() convenience function return an iterator over mutably borrowed elements, borrowing the collection mutably.

So do I understand correctly that <C as IntoIterator>.iter() creates references to the elements of the collection as opposed to <C as IntoIterator> that moves the elements of the collection?

iter() is not a method of IntoIterator or any trait, it's just a conventional name for a method that does that. But yeah, the usual semantics are that it borrows the collection and returns shared references to the elements, same as (&collection).into_iter().

2 Likes