% Содержимое структуры

Для начала необходимо разобраться с компоновкой структуры. Vec состоит из трех частей: указатель на место в памяти, размер места в памяти и количество инициализированных элементов.

Наивно полагаем, что нам нужен такой дизайн:

pub struct Vec<T> {
    ptr: *mut T,
    cap: usize,
    len: usize,
}
fn main() {}

И в самом деле это скомпилируется. К сожалению, дизайн неправильный. Во- первых, компилятор даст нам слишком строгую вариантность. Поэтому &Vec<&'static str> нельзя будет использовать, где ожидается &Vec<&'a str>. Что более важно, он даст некорректную информацию о владении анализатору сброса, потому что компилятор будет думать, что мы не хотим владеть никакими значениями типа T. Смотри главу по владениям и временам жизни для всех деталей вариантности и проверки сброса.

Как мы уже видели в главе о владении, следует использовать Unique<T> вместо *mut T, если у нас есть сырой указатель на место в памяти, которым мы владеем. Хотя Unique нестабилен, поэтому нам бы не следовало его использовать.

Поясним, Unique - это обертка вокруг сырого указателя, которая:

  • вариантна над T
  • может владеть значением типа T (для проверки сброса)
  • является Send/Sync, если T - Send/Sync
  • разыменуется в *mut T (поэтому она действует как *mut в нашем коде)
  • Наш указатель никогда не будет нулевым (поэтому Option<Vec<T>> оптимизирован по нулевому указателю)

Мы можем реализовать все эти требования кроме последнего в стабильном Rust:

use std::marker::PhantomData;
use std::ops::Deref;
use std::mem;

struct Unique<T> {
    ptr: *const T,              // *const для вариантности
    _marker: PhantomData<T>,    // Для анализатора сброса
}

// Выведение Send и Sync безопасно, потому что мы уникальные владельцы
// данных. В этом случае Unique<T> это "просто" T.
unsafe impl<T: Send> Send for Unique<T> {}
unsafe impl<T: Sync> Sync for Unique<T> {}

impl<T> Unique<T> {
    pub fn new(ptr: *mut T) -> Self {
        Unique { ptr: ptr, _marker: PhantomData }
    }
}

impl<T> Deref for Unique<T> {
    type Target = *mut T;
    fn deref(&self) -> &*mut T {
        // Нет явного приведения *const к *mut, с одновременным получением
        // ссылки. Поэтому мы просто используем
        // трансмутацию, ведь это все "просто указатели".
        unsafe { mem::transmute(&self.ptr) }
    }
}
fn main() {}

К сожалению, механизмы, позволяющие утверждать, что ваше значение отличается от нуля, нестабильны и вряд ли будут стабилизированы в ближайшее время. Поэтому, ладно, примем удар и используем Unique из стандартной библиотеки:

#![feature(unique)]

use std::ptr::{Unique, self};

pub struct Vec<T> {
    ptr: Unique<T>,
    cap: usize,
    len: usize,
}

fn main() {}

Если вы не волнуетесь за оптимизацию нулевого указателя, можете использовать стабильный код. Однако мы будет проектировать остальной код, обладая этой оптимизацией. В частности, Unique::new вызывать небезопасно, потому что, если передавать null, то получишь Неопределенное Поведение. Нашему стабильному Unique не нужен небезопасный new, потому что он не дает никаких интересных гарантий своего содержимого.