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);
}