【发布时间】:2020-12-03 20:12:45
【问题描述】:
我有一个无法轻易复制的可变数据结构 (fruitlist: Vec<&mut Groceries>)。我想反复更新和输出它。这是一个最小的例子:
// 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.
}
这会失败,因为 fruitlist 正在移动:
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
当我注释掉更新时,代码运行良好。
我发现自己一次又一次地以不同的形式遇到这个问题。我怎样才能使这种模式起作用?或者有没有更好的方法来重复更新和输出复杂的数据结构?
(另外定义fruitlist_immutable_references的那一行也很丑,希望有更好的办法)
【问题讨论】:
-
如果你的问题在移动,那就不要移动!
update_groceries可以接受groceries: &mut Vec<&mut Groceries>(或切片,如已发布的答案中,这稍微更惯用,但可能会偏离重点)。调用更新时,您将杂货的引用传递为&mut groceries,瞧,没有任何动作发生并且代码编译。
标签: rust lifetime borrow-checker ownership borrowing