[英]Iterating over a vector of mutable references to trait objects
I have a struct
that holds mutable references to trait objects: 我有一个
struct
,其中包含对特征对象的可变引用:
trait Task {
fn do_it(&mut self);
}
struct Worker<'a> {
tasks: Vec<&'a mut Task>,
}
In a method of Worker
, I want to iterate over the tasks and call their do_it
: 在一种
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();
}
}
Sadly, the borrow checker does not let me 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
I cannot make Worker
generic because I want it to hold tasks of many types. 我无法使
Worker
通用性,因为我希望它可以容纳许多类型的任务。 I also need tasks to be mutable. 我还需要可变的任务。 How do I do it in Rust?
如何在Rust中完成?
You are calling tasks.iter()
which produces immutable references to the elements of Vec
. 您正在调用
tasks.iter()
,它生成对Vec
元素的不可变引用。 You actually get back &&mut Task
, an immutable reference to a mutable one (that is why the Rust compiler is complaining). 您实际上返回了
&&mut Task
,它是对可变&&mut Task
的不变引用(这就是Rust编译器抱怨的原因)。
To solve this, call tasks.iter_mut()
to get an iterator of mutable references. 要解决此问题,请调用
tasks.iter_mut()
以获得可变引用的迭代器。
The second problem is calling defining work_one
as a method. 第二个问题是调用将
work_one
定义为方法。 You already borrow a mutable reference from self
when iterating, so you cannot get another borrow. 迭代时,您已经从
self
借来了可变的引用,因此您无法再借用。
Working example ( 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();
}
}
To still have access to self
in work_one
this workaround can be used. 要仍然在
work_one
访问self
,可以使用此替代方法。 This basically just swaps the two vectors so you do not actually borrow self
when iterating and then swapping it back. 基本上,这只是交换两个向量,因此您在迭代然后将其交换回时实际上并不借用
self
。 This is ugly, there may be a better pattern here, maybe someone else will suggest something better. 这很丑陋,这里可能会有更好的模式,也许其他人会提出更好的建议。
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);
}
A nicer alternative suggested by @Veedrac: @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;
}
You need to have a mutable reference to each item. 您需要对每个项目都有可变的引用。
iter
returns immutable references. iter
返回不可变的引用。 And a immutable reference to a mutable variable is not itself mutable. 对可变变量的不可变引用本身并不是可变的。 Use
iter_mut
or for task in &mut self.tasks
instead. 请使用
iter_mut
或将其for task in &mut self.tasks
。
Then, the easiest thing to do is to inline work_one
into work
: 然后, 最简单的方法是将
work_one
内联到work
:
pub fn work(&mut self) {
for task in self.tasks.iter_mut() {
task.do_it()
}
}
Unfortunately, splitting this into two functions is quite painful. 不幸的是,将其分为两个功能非常痛苦。 You have to guarantee that calling
self.work_one
will not modify self.tasks
. 您必须保证调用
self.work_one
不会修改self.tasks
。 Rust doesn't track these things across function boundaries, so you need to split out all the other member variables and pass them separately to a function. Rust不会跨函数边界跟踪这些事情,因此您需要拆分所有其他成员变量并将其分别传递给函数。
See also: 也可以看看:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.