Vectors
Vectors
Вектор - множество данных одного типа, количество которых можно изменять: добавлять и удалять элементы. Нужен, когда:
- требуется собрать набор элементов для обработки в других местах;
- нужно выставить элементы в определённом порядке, с добавлением новых элементов в конец;
- нужно реализовать стэк;
- нужен массив изменяемой величины и расположенный в куче.
Методы
// Задание пустого вектора:
// let mut a test_vector: Vec<i32> = Vec::new();
// Задание вектора со значениями через макрос:
let mut test_vector = vec![1, 2, 3, 4];
test_vector.push(42); // добавить число 42 в конец mut вектора
let Some(last) = test_vector.pop(); // удаляет и возвращает последний элемент (возвращает Option<T>)
test_vector.remove(0); // удалить первый элемент =1
for i in &mut test_vector { // пройти вектор как итератор для вывода
*i += 1; // изменять значения при их получении требует делать '*' dereference
println!("{i}"); }
println!("Vector length: {}", test_vector.len()); // количество элементов
Получение элемента вектора
Элемент можно получить либо с помощью индекса, либо с помощью безопасного метода get:
let mut test_vector = vec![1,2,3,4,5];
println!("Third element of vector is: {}", &test_vector[2]); // индекс
let third: Option<&i32> = test_vector.get(2); // безопасный метод get
match third {
Some(third) => println!("Third element of vector is: {}", third),
None => println!("There is no third element")
}Разница в способах в реакции на попытку взять несуществующий элемент за пределами вектора. Взятие через индекс приведёт к панике и остановке программы. Взятие с помощью get сопровождается проверкой и обработкой ошибки.
Удаление элемента
Метод .remove(index):
let mut numbers = vec![1, 2, 3, 4];
numbers.remove(1); // удаляет элемент с индексом 1
println!("{:?}", numbers); // [1, 3, 4]
.remove()сдвигает все последующие элементы, что может быть дорого для больших векторов (O(n));- Возвращает удалённый элемент;
- Требует
mut, так как изменяет вектор; - Индекс должен быть в пределах длины, иначе паника.
Хранение элементов разных типов в векторе
Rust нужно заранее знать при компиляции, сколько нужно выделять памяти под каждый элемент. Если известны заранее все типы для хранения, то можно использовать промежуточный enum:
#[derive(Debug)]
enum SpreadSheet {
Int(i32),
Float(f64),
Text(String)
}
fn main() {
let row = vec![
SpreadSheet::Int(42),
SpreadSheet::Float(3.14),
SpreadSheet::Text(String::from("red"))
];
for i in row {
println!("{:?}",i);
} }Vector со строками String
let mut v: Vec<String> = Vec::new();Пустой вектор с нулевыми строками можно создать через Default размером до 32 элементов (Rust 1.47):
let v: [String; 32] = Default::default();Вектор большего размера можно создать через контейнер Vec:
let mut v: Vec<String> = vec![String::new(); 100];Вектор с заданными строками можно инициализировать либо с помощью метода to_string(), либо через определение макроса:
macro_rules! vec_of_strings {
($($x:expr),*) => (vec![$($x.to_string()),*]);
}
fn main()
{
let a = vec_of_strings!["a", "b", "c"];
let b = vec!["a".to_string(), "b".to_string(), "c".to_string()];
assert!(a==b); // True
}Соединение вектора со строками в строку (Join):
result_vec.join(" "); // указывается разделитель для соединения
// в старых версиях Rust <1.3 применяют метод .connect();
Сортировка
let number_vector = vec!(1,12,3,1,5);
number_vector.sort(); // 1,1,3,5,12
Способы реверс-сортировки
Смена элементов при сравнении, метод .sort_by() принимает замыкание (closure) для пользовательской сортировки:
number_vector.sort_by(|a,b| b.cmp(a));|a, b|— это замыкание;b.cmp(a)возвращает порядок:Ordering::Less,EqualилиGreater. Инверсия (b.cmp(a)вместоa.cmp(b)) даёт убывающий порядок. Альтернатива:.sort_by_key()для сортировки по вычисляемому ключу:
let mut numbers = vec![3, 1, 4, 1, 5];
numbers.sort_by_key(|&x| -x); // по убыванию через отрицание
println!("{:?}", numbers); // [5, 4, 3, 1, 1]
Сортировка, потом реверс:
number_vector.sort();
number_vector.reverse();Обёртка Reverse с экземпляром Ord:
use std::cmp::Reverse;
number_vector.sort_by_key(|w| Reverse(*w));Если вернуть Reverse со ссылкой и без *, это приведёт к проблеме с временем жизни.
Сортировка вектора по ключу
use std::collections::HashSet;
fn main() {
let mut vowels = HashSet::new();
vowels.insert('e');
vowels.insert('a');
vowels.insert('i');
vowels.insert('o');
vowels.insert('u');
// Конвертация в Vec и сортировка
let mut vowel_vec: Vec<char> = vowels.into_iter().collect();
// Свой порядок сортировки: a, e, i, o, u
let vowel_order = |c: &char| match c {
'a' => 0,
'e' => 1,
'i' => 2,
'o' => 3,
'u' => 4,
_ => 5,
};
vowel_vec.sort_by_key(vowel_order);
println!("Sorted vowels: {:?}", vowel_vec); // ['a', 'e', 'i', 'o', 'u']
}Дедупликация вектора
Удаление одинаковых элементов в векторе, похоже на работу с HashSet.
let s = "aabbccdddeeeeffffeee";
let mut chars: Vec<char> = s.chars().collect();
// Сначала отсортировать, чтобы собрать одинаковые элементы вместе
chars.sort_unstable();
// dedup() удаляет на месте одинаковые СТОЯЩИЕ РЯДОМ в векторе элементы
chars.dedup();
// собрать назад в String:
let unique_s: String = chars.into_iter().collect();Получение вектора из итератора
let collected_iterator: Vec<i32> = (0..10).collect();
println!("Collected (0..10) into: {:?}", collected_iterator);
// Collected (0..10) into: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Конвертация
Конвертация из массива array в vector:
let number_list = [1,12,3,1,5,2];
let number_vector = number_list.to_vec(); // перевод array[i32] -> vector<i32>
Вариант через итератор:
let a = [10, 20, 30, 40];
let v: Vec<i32> = a.iter().map(|&e| e as i32).collect();
Вектор из байтов vector of bytes в строку String:
use std::str;
fn main() {
let buf = &[0x41u8, 0x41u8, 0x42u8]; // vector of bytes
let s = match str::from_utf8(buf) {
Ok(v) => v,
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
};
println!("result: {}", s);
}