我正在尝试使用 Rust 构建一个任务管理器来进行练习。
我想要一个存档的任务部分,所以这是我的任务管理器结构:
pub struct TaskManager {
tasks: Vec<Task>,
archived_tasks: Vec<Task>,
}
我有公开任务和存档任务的功能:
impl TaskManager {
pub fn tasks(&self) -> &Vec<Task> {
&self.tasks
}
pub fn tasks_mut(&mut self) -> &mut Vec<Task> {
&mut self.tasks
}
pub fn archived_tasks(&self) -> &Vec<Task> {
&self.archived_tasks
}
pub fn archived_tasks_mut(&mut self) -> &mut Vec<Task> {
&mut self.archived_tasks
}
}
然后,我有一个可以归档有效任务的功能:
impl TaskManager {
pub fn archive_task(&mut self, idx: usize) -> Result<(), String> {
match self.tasks.get(idx) {
Some(_) => {
self.archived_tasks.push(self.tasks.remove(idx));
Ok(())
},
None => Err("No task with that index".to_string())
}
}
}
然后...借用检查器。我无法执行此操作或类似操作,因此我无法迭代我的任务并调用
archive_task
:
impl App {
fn archive_done_tasks(&mut self) {
for (idx, task) in self.task_manager.tasks().iter().enumerate() {
if task.done() {
self.task_manager.archive_task(idx);
}
}
}
}
编译器当然会抱怨:
error[E0502]: cannot borrow `self.task_manager` as mutable because it is also borrowed as immutable
--> src/app.rs:194:17
|
192 | for (idx, task) in self.task_manager.tasks().iter().enumerate() {
| --------------------------------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
193 | if task.done() {
194 | self.task_manager.archive_task(idx);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
有什么我遗漏的或者我想做的事情是不可能的吗?
正如错误消息所指出的,如果 task_manager 已被借用,则无法获得对它的可变引用。
事实上,这个编译器错误阻止了代码中的错误。
如果允许的话,
archive_task
将从tasks
向量中删除项目,而archive_done_tasks
则对其进行迭代。这会导致一些严重的错误,但幸运的是 rust 可以防止此类问题。
避免添加或删除项目的常见模式是将逻辑分为两遍
请记住,当删除元素时,它会将每个元素的索引更改为右侧。
let mut indices: Vec<usize> = tm.tasks().iter().enumerate()
.filter(|(_, task)| task.done())
.map(|(idx, _)| idx)
.collect();
indices.sort();
for (offset, idx) in indices.into_iter().enumerate() {
tm.archive_task(idx-offset);
}