Sorry if this is a stupid question, but I’m struggling with what I think is ownership in rust.
I’m completely new to rust, but have done low level languages before so I know the concept of pointers pretty well. However, this rust ownership I can’t quite wrap my head around.
I’m trying to refactor my solution to AoC Day 4 Part 2 using a struct reference instead of a stand-alone vector.
The error I’m getting, and can’t figure out is in the process function at line
cards.iter_mut().for_each(|card | {
The error is
cannot borrow cards
as mutable more than once at a time second mutable borrow occurs here
There is a lot of parsing in my code, so I stuck that in a spoiler below.
The relevant code is:
#[derive(Debug)]
struct Card {
id: u32,
score: u32,
copies: u32,
}
fn process(input: &str) -> u32 {
let mut cards: Vec = parse_cards(input);
cards.iter_mut().for_each(|card| {
let copy_from = card.id as usize + 1;
let copy_to: usize = copy_from + card.score as usize - 1;
if card.score == 0 || copy_from > cards.len() {
return;
}
for card_copy in cards[copy_from - 1..copy_to].iter() {
let id = card_copy.id as usize - 1;
let add = cards[card.id as usize - 1].copies;
cards[id].copies += add;
}
});
return cards.iter().map(|c| c.copies).sum();
}
Other code:
spoiler
fn main() {
let input = include_str!("./input1.txt");
let output = process(input);
dbg!(output);
}
fn parse_cards(input: &str) -> Vec {
return input.lines().map(|line| parse_line(line)).collect();
}
fn parse_line(line: &str) -> Card {
let mut card_split = line.split(':');
let id = card_split
.next()
.unwrap()
.replace("Card", "")
.trim()
.parse::()
.unwrap();
let mut number_split = card_split.next().unwrap().trim().split('|');
let winning: Vec = number_split
.next()
.unwrap()
.trim()
.split_whitespace()
.map(|nbr| nbr.trim().parse::().unwrap())
.collect();
let drawn: Vec = number_split
.next()
.unwrap()
.trim()
.split_whitespace()
.map(|nbr| nbr.trim().parse::().unwrap())
.collect();
let mut score = 0;
for nbr in &drawn {
if winning.contains(&nbr) {
score = score + 1;
}
}
return Card {
id,
score,
copies: 1,
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn full_test() {
let result = process(
"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11",
);
assert!(result != 0);
assert_eq!(result, 30);
}
}
I solved it by using indicies instead, that way I got around the borrow checker.
That’s actually what the comment above was suggesting, which is why I was wondering why you couldn’t get it to work. Glad you got it working!