Введение
Переменная хранит одно значение, однако многим программам нужен упорядоченный список, длина которого может изменяться. Vec<T> в Rust — это расширяемая последовательность: каждый элемент имеет тип T, элементы сохраняют свой порядок, а сам вектор владеет ими.
Вы создадите список заказов в кафе, безопасно прочитаете один элемент по позиции, переберёте все заказы, не потребляя список, а затем измените каждую сохранённую строку через изменяемые ссылки.
Создание и расширение вектора
На этом шаге вы добавите три строки, которыми владеет вектор, в изначально пустой вектор.
Перейдите в подготовленный проект и откройте его исходный файл:
cd /home/labex/project/cafe-orders
nano src/main.rs
Объявление Vec<String> означает «вектор, элементы которого являются значениями String, которыми владеет вектор». Это та же угловая скобочная запись для контейнерных типов, которую вы видели в Option<u32>: здесь тип содержащихся элементов — String. Позже, в лабораторной работе по обобщённым типам, вы узнаете, как определять такие универсальные типы. Vec::new() создаёт пустой вектор. Связь объявлена с mut, потому что добавление элементов изменяет вектор.
Замените комментарий шага 1 тремя вызовами push:
orders.push(String::from("Latte"));
orders.push(String::from("Tea"));
orders.push(String::from("Cake"));
push добавляет один элемент в конец вектора, сохраняя порядок вставки. Сохраните файл с помощью Ctrl+O, нажмите Enter, затем выйдите с помощью Ctrl+X. Проверьте код и запустите программу:
cargo check
cargo run --quiet
Вывод должен быть таким:
Order count: 3
Orders: ["Latte", "Tea", "Cake"]
len() сообщает, что в векторе три элемента. Заполнитель :? использует отладочное форматирование Rust, чтобы вывести весь вектор, включая кавычки вокруг строк.
Безопасное чтение элемента по позиции
На этом шаге вы прочитаете второй элемент вектора, не рискуя получить панику из-за выхода за границы.
Нумерация позиций вектора начинается с нуля, поэтому индекс 1 обозначает второй заказ. Метод get возвращает Option<&String>: Some содержит общую ссылку, если указанная позиция существует, а None означает, что позиция отсутствует. Ссылка позволяет прочитать элемент, пока вектор сохраняет владение им.
Откройте исходный файл:
nano src/main.rs
Замените комментарий шага 2 следующим кодом:
match orders.get(1) {
Some(order) => println!("Second order: {order}"),
None => println!("Second order: missing"),
}
Этот код читает элемент, не перемещая его String из вектора. Сохраните файл и выйдите из редактора, затем запустите программу:
cargo run --quiet
В конце вывода должна появиться новая строка:
Second order: Tea
Эта строка подтверждает, что позиция 1 существует и что порядок вставки сохранился.
Перебор с общей ссылкой
На этом шаге вы переберёте все заказы, сохранив возможность использовать вектор после цикла.
Запись &orders заимствует вектор, а не перемещает его в цикл for. Поэтому каждое значение цикла является общей ссылкой на одну сохранённую строку String.
Откройте исходный файл:
nano src/main.rs
Замените комментарий шага 3 этим циклом и следующей проверкой:
for order in &orders {
println!("Queued: {order}");
}
println!("Stored after display: {}", orders.len());
Сохраните файл и выйдите из редактора, затем запустите программу:
cargo run --quiet
Новые строки должны выглядеть так:
Queued: Latte
Queued: Tea
Queued: Cake
Stored after display: 3
Итоговое количество можно получить после цикла, потому что цикл заимствовал вектор и возвращал каждую общую ссылку перед переходом к следующей итерации.
Изменение через изменяемые ссылки
На этом шаге вы получите изменяемую ссылку на каждый элемент вектора и измените элементы непосредственно перед выполнением цикла вывода.
Для одного значения одновременно может существовать только одна изменяемая ссылка. Цикл for по &mut orders соблюдает это правило: он предоставляет изменяемую ссылку на один элемент, использует её в текущей итерации, а затем переходит к следующему элементу.
Откройте исходный файл:
nano src/main.rs
Замените комментарий шага 4 следующим кодом:
for order in &mut orders {
order.push_str(" - ready");
}
push_str добавляет заимствованный текст к каждой строке String, которой владеет вектор. При вызове этого метода Rust автоматически использует изменяемый объект String, на который указывает текущая ссылка.
Сохраните файл и выйдите из редактора, затем проверьте код и запустите программу:
cargo check
cargo run --quiet
Полный вывод должен быть таким:
Order count: 3
Orders: ["Latte", "Tea", "Cake"]
Second order: Tea
Queued: Latte - ready
Queued: Tea - ready
Queued: Cake - ready
Stored after display: 3
Обновлённые строки очереди подтверждают, что все элементы были изменены непосредственно в векторе. Итоговое количество подтверждает, что вектор по-прежнему владеет теми же тремя строками.
Итоги
Вы создали и расширили Vec<String>, безопасно обратились к элементу по позиции с помощью get, перебрали вектор, не потребляя его, и изменили каждый элемент через изменяемые ссылки.


