Reputation: 754
I have a mutable data structure (fruitlist: Vec<&mut Groceries>
) that can't be easily copied. I want to repeatedly update and output it. Here is a minimal example:
// Note that Groceries do not implement the Copy trait
struct Groceries {
amount: u32,
item: String,
}
// takes mutable references because we will alter the Groceries
fn update_groceries(groceries: Vec<&mut Groceries>) {
// Double everything we have, just in case of a pandemic
for g in groceries {
g.amount *= 2;
}
}
// takes immutable references because we will only need to read them
fn output_groceries(groceries: Vec<&Groceries>) {
for g in groceries {
println!("{}: {}", g.item, g.amount);
}
}
fn main() {
// We start with a list of fruit
let mut bananas: Groceries = Groceries{amount:3, item: String::from("yellow bananas")};
let mut oranges: Groceries = Groceries{amount:2, item: String::from("oranges")};
let fruitlist: Vec<&mut Groceries> = vec![
&mut bananas,
&mut oranges,
];
// Now we want to update and print the list
update_groceries(fruitlist);
// the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>
let fruitlist_immutable_references: Vec<& Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
output_groceries(fruitlist_immutable_references);
// This update and print part might happen multiple times in a loop.
}
This fails because the fruitlist
is getting moved:
error[E0382]: use of moved value: `fruitlist`
--> src/main.rs:38:60
|
29 | let fruitlist: Vec<&mut Groceries> = vec![
| --------- move occurs because `fruitlist` has type `std::vec::Vec<&mut Groceries>`, which does not implement the `Copy` trait
...
36 | update_groceries(fruitlist);
| --------- value moved here
37 | // the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>
38 | let fruitlist_immutable_references: Vec<& Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
| ^^^^^^^^^ value used here after move
The code works fine when I comment out the updating.
I find myself running into this problem in different forms again and again. How can I make this pattern work? Or is there a better way to update and output a complex data structure repeatedly?
(Also the line defining fruitlist_immutable_references
is pretty ugly. I hope that there is a better way)
Upvotes: 0
Views: 54
Reputation: 15135
If you pass the list by value (e.g. list: Vec<&mut Groceries>
) into a function then it moves the ownership of the list into the function. Instead you should pass it by reference (e.g. list: &mut [&mut Groceries]
, or list: &[&Groceries]
) to maintain ownership of the list. Fixed example:
// Note that Groceries do not implement the Copy trait
struct Groceries {
amount: u32,
item: String,
}
// takes mutable references because we will alter the Groceries
fn update_groceries(groceries: &mut [&mut Groceries]) {
// Double everything we have, just in case of a pandemic
for g in groceries {
g.amount *= 2;
}
}
// takes immutable references because we will only need to read them
fn output_groceries(groceries: &[&Groceries]) {
for g in groceries {
println!("{}: {}", g.item, g.amount);
}
}
fn main() {
// We start with a list of fruit
let mut bananas: Groceries = Groceries { amount:3, item: String::from("yellow bananas") };
let mut oranges: Groceries = Groceries { amount:2, item: String::from("oranges") };
let mut fruitlist: Vec<&mut Groceries> = vec![
&mut bananas,
&mut oranges,
];
// Now we want to update and print the list
update_groceries(&mut fruitlist);
// the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>
let fruitlist_immutable_references: Vec<&Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
output_groceries(&fruitlist_immutable_references);
// This update and print part might happen multiple times in a loop.
}
Upvotes: 4