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 вектора
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
сопровождается проверкой и обработкой ошибки.
Хранение элементов разных типов в векторе
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
Способы реверс-сортировки
Смена элементов при сравнении:
number_vector.sort_by(|a,b| b.cmp(a));
Сортировка, потом реверс:
number_vector.sort();
number_vector.reverse();
Обёртка Reverse с экземпляром Ord:
use std::cmp::Reverse;
number_vector.sort_by_key(|w| Reverse(*w));
Если вернуть Reverse со ссылкой и без *
, это приведёт к проблеме с временем жизни.
Получение вектора из итератора
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);
}