I'm trying to create a ToDo Application, for now, it's a simple task app that has a single struct (task).
Ask: I need to start keeping the full list of tasks somewhere, so the user can query the full list of tasks, and eventually filter them. However, I'm having trouble creating something that the compiler allows.
I'm new to rust in general, so thank you for your patience
As you can see, i'm trying a very simple format where I create a global vector (since it should only have tasks inside of it) and upon the creation of a new task, I want to be able to add the new task to the vector, and change the tasks by searching within this vector.
Am I just going about this wrong? or is there an easy way to get this format to work?
Thank you in advance for your patience and expertise.
Then, instead of it being a global, you can probably get away with it being a local variable in main that has references passed around your program. Among other things, this lets individual #[test] functions operate in parallel on their own copies of a TaskList.
If you then decide that you need to have a global task list available, you’ll be able to use something like the lazy_static or once_cell crates to create a global Mutex<TaskList> without needing to intersperse synchronization code with your main program logic.
This is a wonderful solution. Thank you for your quick and thorough response!
Quick semantics question: why do you use the 0 in your reference to the vector? is that referring to the 0th index? or is this the 0th vector in the struct?
In this case, TaskList is defined to have a single anonymous field of type Vec<Task> which then gets accessed as task_list.0. You could as easily define it like this:
pub struct TaskList {
tasks: Vec<Task>
}
and then replace every self.0 with self.tasks. The final generated code should be the same.
It's generally better to encode something like that in an enum, especially if the range of valid values is so low.
#[repr(u8)] // To have the same layout as a u8
#[derive(Debug)] // Enable pretty printing (optional)
enum Priority {
Highest = 1,
High = 2,
Medium = 3,
Low = 4,
Lowest = 5,
}
This both prevents unexpected values in your code and it allows to pretty print the values easily.
If you need to work with the priorities as a u8, you can easily convert them to that:
let x = Priority::Low;
println!("{}", x as u8);
// prints "4"
Converting any u8 to a Priority would be a little different, since that conversion could fail in the general case. You could do it like this, if you need that:
use std::convert::TryInto;
let x: Priority = 1u8.try_into().unwrap();
// this unwrap crashes the program, if the value is not in the range 1-5
println!("{:?}", x);
// prints "Highest"
For the sake of your sanity in Rust, and in programming in general in any language, it is better that you expunge the idea of 'global' from your mind altogether.
You can wrap all your data and the functions that operate on it in a struct and make those functions methods of the struct with impl. With the slight inconvenience that you now need to refer to what may have been globals with self.whatever
Which I guess is what has been suggested above.
My only little point is that setting out to create a global anything it is almost always the wrong way to think about whatever problem you have and creating globals is not the problem you actually want to solve anyway.