Hi,
I'm trying to build a todo app to learn Rust, but I'm a bit stuck.
Currently I have a todo_list
struct that holds all todos, and I also operate on that one to create or delete items.
However, since I want to display daily, weekly, monthly and yearly todos later in different sections on the screens, I have getters for each one respectively.
Now having the code as below, I run into errors with the borrowing rules. Since I have a mutable borrow on the todo_list
variable so I can add and delete items, I can't add another borrow for my specific getters such as daily_todos
.
I understand the rules that I can have as many immutable borrows, but as soon as I have a mutable one that's is, this is the one and only. But now I can't think of how to make this work. I'm starting to think that my approach is flawed from the beginning regarding the data structure, but I wanted to ask for some help here first because I really am stuck.
#[derive(Debug, PartialEq)]
pub enum TodoType {
Daily,
Weekly,
}
#[derive(Debug, PartialEq)]
pub struct TodoItem {
id: String,
name: String,
completed: bool,
comment: Option<String>,
todo_type: TodoType,
}
#[derive(Debug, Default)]
pub struct TodoList {
todos: Vec<TodoItem>,
}
impl TodoItem {
fn new(item: String, comment: Option<String>, todo_type: TodoType) -> Self {
Self {
id: "1".to_string(),
name: item,
completed: false,
comment,
todo_type,
}
}
}
impl TodoList {
pub fn new() -> Self {
Self { todos: vec![] }
}
// Getters
pub fn get_daily(&self) -> Vec<&TodoItem> {
self.get_todos(TodoType::Daily)
}
pub fn get_weekly(&self) -> Vec<&TodoItem> {
self.get_todos(TodoType::Weekly)
}
fn get_todos(&self, todo_type: TodoType) -> Vec<&TodoItem> {
self.todos
.iter()
.filter(|todo| todo.todo_type == todo_type)
.collect()
}
// Adders
pub fn add_daily_todo(&mut self, item: String, comment: Option<String>) {
self.add_todo(item, comment, TodoType::Daily)
}
pub fn add_weekly_todo(&mut self, item: String, comment: Option<String>) {
self.add_todo(item, comment, TodoType::Weekly)
}
fn add_todo(&mut self, item: String, comment: Option<String>, todo_type: TodoType) {
self.todos.push(TodoItem::new(item, comment, todo_type))
}
// Removers
pub fn remove_todo_by_id(&mut self, id: &String) {
self.todos.retain_mut(|item| item.id != *id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_delete_a_daily_todo() {
let mut todo_list = TodoList::new();
todo_list.add_daily_todo("D1".to_string(), None);
todo_list.add_daily_todo("D2".to_string(), None);
let daily_todos = todo_list.get_daily();
// check initial state
assert_eq!(daily_todos.len(), 2);
assert_eq!(daily_todos[0].name, "D1".to_owned());
assert_eq!(daily_todos[1].name, "D2".to_owned());
// delete first todo
todo_list.remove_todo_by_id(&daily_todos[0].id);
// check updated todo list
assert_eq!(daily_todos.len(), 1);
assert_eq!(daily_todos[0].name, "D2".to_owned());
}
}
This gives me the following error on the test:
But I can't change the get_daily to a mutable borrow, since then it complains about
cannot borrow
todo_list as mutable more than once at a time
Would appreciate some help here