Векторы в Rust
Вектор (Vec) похож на массив, но может расти и уменьшаться во время работы программы. В повседневном коде на Rust, когда нужен список чего-то, ты будешь брать Vec гораздо чаще, чем массив фиксированного размера.
Создаём вектор
Заголовок раздела «Создаём вектор»fn main() { let numbers: Vec<i32> = vec![1, 2, 3]; println!("{:?}", numbers);}vec![] — это макрос (обрати внимание на !), который собирает Vec из списка значений, почти как литерал массива.
Можно начать и с пустого вектора и заполнять его постепенно:
let mut numbers: Vec<i32> = Vec::new();Добавляем элементы
Заголовок раздела «Добавляем элементы».push() добавляет элемент в конец. Вектор должен быть mut, ведь ты его меняешь:
fn main() { let mut numbers = Vec::new();
numbers.push(1); numbers.push(2); numbers.push(3);
println!("{:?}", numbers);}Вывод:
[1, 2, 3]Доступ к элементам
Заголовок раздела «Доступ к элементам»Те же квадратные скобки, что и у массивов:
fn main() { let fruits = vec!["яблоко", "банан", "вишня"];
println!("{}", fruits[0]); println!("Длина: {}", fruits.len());}Для более безопасного доступа, который не паникует на неверном индексе, используй .get() — он возвращает Option (подробнее — в уроке Option):
fn main() { let fruits = vec!["яблоко", "банан", "вишня"];
match fruits.get(10) { Some(fruit) => println!("Нашли: {fruit}"), None => println!("По этому индексу фрукта нет"), }}Удаляем элементы
Заголовок раздела «Удаляем элементы»fn main() { let mut numbers = vec![1, 2, 3, 4, 5];
numbers.pop(); // удаляет последний элемент -> [1, 2, 3, 4] numbers.remove(0); // удаляет по индексу -> [2, 3, 4]
println!("{:?}", numbers);}Перебираем вектор
Заголовок раздела «Перебираем вектор»fn main() { let numbers = vec![10, 20, 30];
for n in &numbers { println!("{n}"); }}Обрати внимание на & перед numbers: цикл for n in &numbers заимствует каждый элемент, а не забирает владение вектором. Если убрать &, вектор переместится в цикл, и после него пользоваться numbers будет нельзя. Почти всегда тебе нужно именно заимствование.
Пара слов об обобщениях
Заголовок раздела «Пара слов об обобщениях»Ты заметил, что тип записан как Vec<i32>: часть <i32> говорит «вектор из значений i32». Такая запись в угловых скобках называется обобщением (generic), и как следует мы разберём её в уроке Обобщения. Пока просто читай Vec<T> как «вектор со значениями типа T».
Практика
Заголовок раздела «Практика»1. Собираем чётные числа
Заголовок раздела «1. Собираем чётные числа»Начни с пустого вектора. Перебери числа от 1 до 10 и добавляй только чётные. Затем выведи вектор и количество элементов в нём. Подсказка: число n чётное, когда n % 2 == 0.
Показать решение
fn main() { let mut evens = Vec::new();
for n in 1..=10 { if n % 2 == 0 { evens.push(n); } }
println!("{:?}", evens); println!("Нашли чётных чисел: {}", evens.len());}Вывод:
[2, 4, 6, 8, 10]Нашли чётных чисел: 5Заметь, тип мы так и не написали. Rust видит вызовы push(n) и сам понимает, что evens — это Vec<i32>.
2. Стопка тарелок
Заголовок раздела «2. Стопка тарелок»Положи в вектор три тарелки: "синяя", "зелёная", потом "красная". Сними две тарелки сверху через .pop() и выведи каждую. В конце выведи, что осталось. Подсказка: .pop() возвращает Option, поэтому выводи его через {:?}.
Показать решение
fn main() { let mut plates = Vec::new(); plates.push("синяя"); plates.push("зелёная"); plates.push("красная");
println!("Сняли {:?}", plates.pop()); println!("Сняли {:?}", plates.pop()); println!("Осталось: {:?}", plates);}Вывод:
Сняли Some("красная")Сняли Some("зелёная")Осталось: ["синяя"]pop() всегда берёт последний добавленный элемент — как верхнюю тарелку из стопки. Он возвращает Some(...), а не само значение, потому что вектор может оказаться пустым. Тогда ты получишь None, а не падение программы.
Vec<T>— растущий список; создаётся черезvec![...]илиVec::new()..push()добавляет в конец,.pop()удаляет последний элемент,.remove(i)удаляет по индексу.vec[i]паникует на неверном индексе, а.get(i)возвращаетOptionи не паникует.- Перебирай через
for item in &vec, чтобы заимствовать элементы, а не поглощать вектор.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Что произойдёт, если обратиться к Vec по неверному индексу, например numbers[10]?
2. Какой метод позволяет обратиться по индексу без риска паники?
3. Что делает & в for n in &numbers?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- Хранение списков значений с векторами — книга «Язык программирования Rust»: создание, чтение и изменение векторов, а также почему нельзя делать
push, пока держишь ссылку (перевод на русский). - Вектора — Rust на примерах: один запускаемый пример с самыми частыми операциями над
Vec(перевод на русский). Vec— документация стандартной библиотеки (на английском): полный список методов, напримерinsert,retain,extendиcontains.- The
vec!macro — документация стандартной библиотеки (на английском): все формыvec!, включаяvec![0; 10]для повторяющихся значений.