1.8 Ревизия
Теоретически, если точно знать количество задач в списке и не забывать, что счёт начинается с нуля, цикл не нужен. Практика показывает, что оба условия нарушаются быстрее, чем ожидается. Особенно второе.
Попытка
Итак, у нас уже сформирован список задач. Хочется пройтись по нему и посмотреть на всё сразу прежде чем добавлять новое. В Rust для этого есть удобная конструкция:
for task in tasks {
println!("#{}: {} - {:?}", task.id, task.title, task.status);
}
tasks.push(Task::new(2, "Buy milk"));
for ... in - цикл: берёт элементы коллекции по очереди, для каждого выполняет тело (между фигурными скобками).
Выглядит хорошо. Но у компилятора есть замечание:
error[E0382]: borrow of moved value: `tasks`
|
| let mut tasks: Vec<Task> = Vec::new();
| --------- move occurs because `tasks` has type `Vec<Task>`,
| which does not implement the `Copy` trait
| for task in tasks {
| ----- `tasks` moved due to this implicit call to `.into_iter()`
| tasks.push(Task::new(2, "Buy milk"));
| ^^^^^ value borrowed here after move
Что знает компилятор
for task in tasks - это перемещение. Цикл забирает tasks целиком и становится его
владельцем. Когда цикл заканчивается, коллекция уничтожается вместе с ним.
Строка с push обращается к тому, чего уже нет.
Мы видели аналогичное в главе 1.5: передать - значит отдать. Только здесь получатель не функция, а цикл.
Решение то же: передать право на чтение, а не владение:
for task in &tasks {
println!("{:?}", task);
}
&tasks - ссылка на коллекцию. Цикл читает через неё; tasks остаётся жить в main.
Заклинание
fn main() {
let mut tasks: Vec<Task> = Vec::new();
tasks.push(Task::new(1, "Buy coffee"));
let task = &mut tasks[0];
println!("#{}: {}", task.id, task.title);
task.complete();
if task.is_done() {
println!("Task 1 done");
}
tasks.push(Task::new(2, "Buy milk"));
tasks.push(Task::new(3, "Buy eggs"));
for task in &tasks {
println!("{:?}", task);
}
}
#1: Buy coffee
Task 1 done
Task { id: 1, title: "Buy coffee", status: Done }
Task { id: 2, title: "Buy milk", status: Todo }
Task { id: 3, title: "Buy eggs", status: Todo }
make ci проходит. А мы знаем как сделать ревизию всей коллекции.
Полный код
tqдля этой главы -1-a-task/08-the-inventory/.