Для хранения набора однотипных данных в языке Rust предназначены массивы. Однако они имеют недостаток - после их определения мы не можем изменить их длину, не можем
ни добавить новый элемент, ни удалить уже существующий. Этот недостаток призван устранить вектор, который представлен типом
Vec<T> (а точнее структурой std::vec::Vec<T>
). Вектор как раз и представляет динамически изменяемый набор однотипных данных.
Есть разные способы определения вектора. Первый способ - вызов функции Vec::new(), которая создает пустой вектор:
let v: Vec<тип_данных> = Vec::new();
Например:
let v: Vec<i32> = Vec::new();
В данной случае также указан тип вектора - Vec<i32> - то есть вектор, который хранит значения типа i32.
Второй способ представляет применение специального макроса vec!, после которого в квадратных скобках через запятую перечисляются элементы вектора:
let v = vec! [значение1, значени2, ... значениеN];
Например:
let v = vec![1, 2, 3];
Здесь для вектора определены три элемента типа i32, поэтому вектор неявно будет иметь тип Vec<i32>
При этом вектор может быть и пустым:
let v: Vec<i32>= vec![];
Третий способ представляет заполнение вектора значениями по умолчанию:
let v = vec![val; repeat];
В квадратных скобках после макроса vec!
указываются два значения. Первое значение указывает на значение по умолчанию, которым заполняется вектор, а второе значение -
начальное количество элементов. Например:
let v = vec![5; 3];
Этот вектор будет аналогичен следущему:
let v = vec![5, 5, 5];
Для добавления элементов в вектор применяется метод push():
let mut users = Vec::new(); users.push("Tom"); users.push("Sam"); users.push("Bob");
Причем если предполагается изменение вектора, то его переменная должна быть определена с помощью оператора mut.
При это в примере выше указан тип вектора, так как Rust на основе добавляемых значений может определить тип. Однако все добавляемые значения, должны иметь один и тот же тип данных.
Обращение к элементам вектора производится так же, как и к элементам массива с помощью индексов:
вектор[индекс_элемента]
Например, получим и изменим некоторые элементы вектора:
fn main(){ let mut users = vec!["Tom", "Sam", "Bob"]; println!("1. {}", users[0]); // Tom println!("2. {}", users[1]); // Sam println!("3. {}", users[2]); // Bob // меняем значение элемента users[1] = "Alice"; println!("После изменения: 2. {}", users[1]); // Alice }
Консольный вывод:
1. Tom 2. Sam 3. Bob После изменения: 2. Alice
Для перебора вектора можно использовать цикл for:
fn main(){ let users = vec!["Tom", "Sam", "Bob"]; for user in &users{ println!("{}", user); } }
Обратите внимания, что циклу for передается не сам объект вектора users, а ссылка на него. Дело в том, что передача объекта в цикл меняет владение вектора. После чего мы не сможем ссылаться на этот вектор через переменную users. Проблему можно увидеть на следующем примере:
fn main(){ let mut users = vec!["Tom", "Sam", "Bob"]; for user in users{ print!("{} ", user); } users.push("Alice"); // ! Ошибка - переменнаяя users более недействительна }
Здесь в цикл передается не ссылка, а полноценный объект вектора. В итоге владение вектором перемещается от переменной users в цикл for. Поэтому на строке
users.push("Alice");
при компиляции мы получим ошибку, так как переменная users больше не представляет объект вектора.
Длина вектора возвращается методом len():
fn main(){ let mut users = vec!["Tom", "Sam", "Bob"]; println!("length: {}", users.len()); // 3 }
Для удаления элемента по индексу применяется метод remove():
fn main(){ let mut users = vec!["Tom", "Sam", "Bob", "Alice"]; let removed_element = users.remove(1); // удаляем второй элемент println!("Удаленный элемент: {}", removed_element); // Sam for user in &users{ print!("{} ", user); // Tom Bob Alice } }
Еще один метод - pop() удаляет элемент из конца вектора и возвращает его:
fn main(){ let mut users = vec!["Tom", "Sam", "Bob", "Alice"]; let removed_element = users.pop(); // удаляем элемент из конца println!("Удаленный элемент: {}", removed_element.unwrap()); // Alice for user in &users{ print!("{} ", user); // Tom Sam Bob } }
В реальности метод pop()
возвращает объект перечисления Option<T>
. И чтобы получить из него содержащийся в нем элемент,
применяется метод unwrap()
: removed_element.unwrap()
.
Это только часть функционала векторов. Все методы вектора можно посмотреть в документации - https://doc.rust-lang.org/std/vec/struct.Vec.html