Динамическое определение размера массивов в Rust: изучение методов и примеры кода

В Rust массивы имеют фиксированный размер, определяемый во время компиляции. Однако существуют различные методы достижения динамического размера или массивов с изменяемым размером. В этой статье блога мы рассмотрим несколько подходов, а также примеры кода, демонстрирующие, как создавать и манипулировать массивами с динамическими размерами в Rust.

Метод 1: Vec
Самый распространенный способ создания массива динамического размера в Rust — использование типа Vec<T>из стандартной библиотеки. Vec<T>— массив с динамически изменяемым размером, предоставляющий удобный интерфейс для управления его размером.

fn main() {
    let mut dynamic_array: Vec<i32> = Vec::new();
    dynamic_array.push(1);
    dynamic_array.push(2);
    dynamic_array.push(3);
    for element in &dynamic_array {
        println!("{}", element);
    }
}

Метод 2: Box<[T]>
Другой подход — использовать Box<[T]>, который представляет собой массив динамического размера, размещенный в куче. Он допускает динамическое изменение размера и может быть полезен в определенных сценариях, где вам нужен больший контроль над распределением памяти.

fn main() {
    let mut dynamic_array: Box<[i32]> = Box::new([]);
    dynamic_array = vec![1, 2, 3].into_boxed_slice();
    for element in dynamic_array.iter() {
        println!("{}", element);
    }
}

Метод 3: VecDeque
Если вам требуется коллекция, которая поддерживает эффективную вставку и удаление на обоих концах, вы можете использовать тип VecDeque<T>. Он предоставляет двустороннюю очередь, которая может действовать как массив с динамически изменяемым размером.

use std::collections::VecDeque;
fn main() {
    let mut dynamic_array: VecDeque<i32> = VecDeque::new();
    dynamic_array.push_front(1);
    dynamic_array.push_back(2);
    dynamic_array.push_back(3);
    for element in dynamic_array.iter() {
        println!("{}", element);
    }
}

Метод 4: собственная реализация динамического массива
В качестве альтернативы вы можете создать собственную реализацию динамического массива, используя необработанные указатели и ручное управление памятью. Этот подход дает вам полный контроль над логикой изменения размера, но требует осторожного обращения с памятью.

struct DynamicArray<T> {
    data: *mut T,
    length: usize,
    capacity: usize,
}
impl<T> DynamicArray<T> {
    fn new() -> Self {
        let capacity = 4;
        let data = unsafe { std::alloc::alloc(Layout::array::<T>(capacity).unwrap()) };
        DynamicArray {
            data,
            length: 0,
            capacity,
        }
    }
    fn push(&mut self, element: T) {
        if self.length == self.capacity {
            self.resize();
        }
        unsafe { std::ptr::write(self.data.add(self.length), element) };
        self.length += 1;
    }
    fn resize(&mut self) {
        let new_capacity = self.capacity * 2;
        let new_data = unsafe { std::alloc::realloc(self.data, Layout::array::<T>(new_capacity).unwrap(), new_capacity) };
        if new_data.is_null() {
            panic!("Failed to resize dynamic array");
        }
        self.data = new_data;
        self.capacity = new_capacity;
    }
}
fn main() {
    let mut dynamic_array: DynamicArray<i32> = DynamicArray::new();
    dynamic_array.push(1);
    dynamic_array.push(2);
    dynamic_array.push(3);
    for i in 0..dynamic_array.length {
        let element = unsafe { *dynamic_array.data.add(i) };
        println!("{}", element);
    }
}

В этой статье мы рассмотрели несколько методов достижения динамического изменения размера массивов в Rust. Мы рассмотрели использование Vec<T>из стандартной библиотеки, Box<[T]>для большего контроля над распределением памяти, VecDeque<T>для эффективной вставки и удаления на обоих концах и даже создание собственной реализации динамического массива. Используя эти методы, вы можете адаптировать массивы в соответствии с вашими конкретными потребностями в программировании на Rust.

Не забудьте выбрать метод, который лучше всего соответствует вашим требованиям, и учитывать компромисс между простотой, производительностью и управлением памятью.