I'm trying to build a task manager with Rust for practice.
I want to have an archived tasks sections, and so this is my task manager struct:
pub struct TaskManager {
tasks: Vec<Task>,
archived_tasks: Vec<Task>,
}
I have functions to make tasks and archived tasks public:
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
}
}
Then, I have a function to archive a task that works:
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())
}
}
}
And then... the borrow checker. I can't do this or anything like it, so I can't iterate over my tasks and call 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);
}
}
}
}
Of course the compiler complains:
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
Is there something I'm missing or what I'm trying to do is not possible?
Instead of using index and allocating memory for them, I propose another solution using iterators:
/// This will require nightly channel
#![feature(extract_if)]
struct Task {
done: bool
}
impl Task {
pub fn done(&self) -> bool {self.done}
}
pub struct TaskManager {
tasks: Vec<Task>,
archived_tasks: Vec<Task>,
}
impl TaskManager {
pub fn archive_done_tasks(&mut self) {
let iter = self.tasks.extract_if(|x| x.done());
self.archived_tasks.extend(iter);
}
}
struct App {
task_manager: TaskManager,
}
impl App {
fn archive_done_tasks(&mut self) {
self.task_manager.archive_done_tasks()
}
}
fn main() {
let mut app = App{task_manager: TaskManager{tasks: vec![], archived_tasks: vec![]}};
app.archive_done_tasks();
println!("Done")
}
If you want to use stable channel you can do its equivalent:
/// Stable channel
struct Task {
done: bool
}
impl Task {
pub fn done(&self) -> bool {self.done}
}
pub struct TaskManager {
tasks: Vec<Task>,
archived_tasks: Vec<Task>,
}
impl TaskManager {
pub fn archive_done_tasks(&mut self) {
let mut i = 0;
while i < self.tasks.len() {
if self.tasks[i].done() {
let val = self.tasks.remove(i);
self.archived_tasks.push(val);
} else {
i += 1;
}
}
}
}
struct App {
task_manager: TaskManager,
}
impl App {
fn archive_done_tasks(&mut self) {
self.task_manager.archive_done_tasks()
}
}
fn main() {
let mut app = App{task_manager: TaskManager{tasks: vec![], archived_tasks: vec![]}};
app.archive_done_tasks();
println!("Done")
}