迭代特征对象的可变引用向量
Iterating over a vector of mutable references to trait objects
我有一个 struct
保存对特征对象的可变引用:
trait Task {
fn do_it(&mut self);
}
struct Worker<'a> {
tasks: Vec<&'a mut Task>,
}
在 Worker
的方法中,我想遍历任务并调用它们的 do_it
:
impl<'a> Worker<'a> {
pub fn work(&mut self) {
for task in self.tasks.iter() {
self.work_one(*task);
}
}
fn work_one(&self, task: &mut Task) {
task.do_it();
}
}
遗憾的是,借阅检查员不让我这样做:
error[E0389]: cannot borrow data mutably in a `&` reference
--> src/main.rs:12:27
|
12 | self.work_one(*task);
| ^^^^^ assignment into an immutable reference
我不能使 Worker
通用,因为我希望它包含多种类型的任务。我还需要可变的任务。我如何在 Rust 中做到这一点?
您需要对每个项目都有一个可变引用。 iter
returns 不可变引用。并且对可变变量的不可变引用本身不是可变的。请改用 iter_mut
或 for task in &mut self.tasks
。
然后,最简单的事情就是将 work_one
内联到 work
:
pub fn work(&mut self) {
for task in self.tasks.iter_mut() {
task.do_it()
}
}
不幸的是,将其拆分为两个函数非常痛苦。你必须保证调用 self.work_one
不会修改 self.tasks
。 Rust 不会跨函数边界跟踪这些东西,因此您需要拆分出所有其他成员变量并将它们分别传递给函数。
另请参阅:
- cannot borrow `self.x` as immutable because `*self` is also borrowed as mutable
您正在调用 tasks.iter()
,它会生成对 Vec
元素的不可变引用。你实际上得到了 &&mut Task
,一个对可变引用的不可变引用(这就是 Rust 编译器抱怨的原因)。
要解决此问题,请调用 tasks.iter_mut()
以获取可变引用的迭代器。
第二个问题是调用定义work_one
作为方法。您在迭代时已经从 self
借用了一个可变引用,因此您无法再次借用。
工作示例(playground):
trait Task {
fn do_it(&mut self);
}
struct Worker<'a> {
tasks: Vec<&'a mut Task>,
}
impl<'a> Worker<'a> {
pub fn work(&mut self) {
for task in self.tasks.iter_mut() {
Worker::work_one(*task);
}
}
fn work_one(task: &mut Task) {
task.do_it();
}
}
要在 work_one
中仍然可以访问 self
,可以使用此解决方法。这基本上只是交换了两个向量,所以你在迭代时实际上并没有借用 self
然后将它交换回来。这很难看,这里可能有更好的模式,也许其他人会提出更好的建议。
pub fn work(&mut self) {
let mut tasks = vec![];
mem::swap(&mut tasks, &mut self.tasks);
for task in tasks.iter_mut() {
self.work_one(*task);
}
mem::swap(&mut tasks, &mut self.tasks);
}
@Veedrac 建议的更好的替代方案:
fn work(&mut self) {
let mut tasks = mem::replace(&mut self.tasks, Vec::new());
for task in &mut tasks {
self.work_one(*task);
}
self.tasks = tasks;
}
我有一个 struct
保存对特征对象的可变引用:
trait Task {
fn do_it(&mut self);
}
struct Worker<'a> {
tasks: Vec<&'a mut Task>,
}
在 Worker
的方法中,我想遍历任务并调用它们的 do_it
:
impl<'a> Worker<'a> {
pub fn work(&mut self) {
for task in self.tasks.iter() {
self.work_one(*task);
}
}
fn work_one(&self, task: &mut Task) {
task.do_it();
}
}
遗憾的是,借阅检查员不让我这样做:
error[E0389]: cannot borrow data mutably in a `&` reference
--> src/main.rs:12:27
|
12 | self.work_one(*task);
| ^^^^^ assignment into an immutable reference
我不能使 Worker
通用,因为我希望它包含多种类型的任务。我还需要可变的任务。我如何在 Rust 中做到这一点?
您需要对每个项目都有一个可变引用。 iter
returns 不可变引用。并且对可变变量的不可变引用本身不是可变的。请改用 iter_mut
或 for task in &mut self.tasks
。
然后,最简单的事情就是将 work_one
内联到 work
:
pub fn work(&mut self) {
for task in self.tasks.iter_mut() {
task.do_it()
}
}
不幸的是,将其拆分为两个函数非常痛苦。你必须保证调用 self.work_one
不会修改 self.tasks
。 Rust 不会跨函数边界跟踪这些东西,因此您需要拆分出所有其他成员变量并将它们分别传递给函数。
另请参阅:
- cannot borrow `self.x` as immutable because `*self` is also borrowed as mutable
您正在调用 tasks.iter()
,它会生成对 Vec
元素的不可变引用。你实际上得到了 &&mut Task
,一个对可变引用的不可变引用(这就是 Rust 编译器抱怨的原因)。
要解决此问题,请调用 tasks.iter_mut()
以获取可变引用的迭代器。
第二个问题是调用定义work_one
作为方法。您在迭代时已经从 self
借用了一个可变引用,因此您无法再次借用。
工作示例(playground):
trait Task {
fn do_it(&mut self);
}
struct Worker<'a> {
tasks: Vec<&'a mut Task>,
}
impl<'a> Worker<'a> {
pub fn work(&mut self) {
for task in self.tasks.iter_mut() {
Worker::work_one(*task);
}
}
fn work_one(task: &mut Task) {
task.do_it();
}
}
要在 work_one
中仍然可以访问 self
,可以使用此解决方法。这基本上只是交换了两个向量,所以你在迭代时实际上并没有借用 self
然后将它交换回来。这很难看,这里可能有更好的模式,也许其他人会提出更好的建议。
pub fn work(&mut self) {
let mut tasks = vec![];
mem::swap(&mut tasks, &mut self.tasks);
for task in tasks.iter_mut() {
self.work_one(*task);
}
mem::swap(&mut tasks, &mut self.tasks);
}
@Veedrac 建议的更好的替代方案:
fn work(&mut self) {
let mut tasks = mem::replace(&mut self.tasks, Vec::new());
for task in &mut tasks {
self.work_one(*task);
}
self.tasks = tasks;
}