Search
Write a publication
Pull to refresh
0
0
Send message

Небольшой вопрос. Зачем использовать PhantomData<T> если T итак тип нулевого размера и не является ничем кроме маркера?

Не скажи. Когда ты работаешь со структурой и принимаешь ее по щаренной или мутабельной ссылке (&self, &mut self), это очень помогает. Ты хотя бы точно знаешь что структура существует и ты можешь спокойно разыменовать self

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

Что мне иногда раздражает, так это то что многие говорят под капотом rust использует много unsafe, и что нельзя превратить unsafe в safe.

Хотя вот пример как из превратить unsafe в safe и получать PROFIT :-). Привожу адаптированный код хеш таблицы из библиотеки hashbrown:

pub struct RawTable<T, A: Allocator + Clone = Global> {
    table: RawTableInner<A>,
    // Tell dropck that we own instances of T.
    marker: PhantomData<T>,
}

pub struct RawTableInner<A> {
    bucket_mask: usize,
    ctrl: *const u8,
    growth_left: usize,
    items: usize,
    alloc: A,
}

pub fn get<F>(&self, hash: u64, eq: F1) -> Option<&T>
where
    F: FnMut(&T) -> bool,
{
    match self.find(hash, eq) {
        // bucket = *mut T
        Some(bucket) => Some(unsafe { &*bucket }),
        None => None,
    }
}

Прикол в том что вроде бы как RawTableInner хранит сырой указатель на аллоцированную память и полностью небезопасен. Но далее привязываем данную таблицы к RawTable + PhantomData что говорит компилятору что у нас владеющая структура. Потом определяем метод get, который внутри использует метод find. Find возвращает сырой указатель. Но!!! Мы ведь определили метод get у &RawTable, а также привязали выходную ссылку на значение к времени жизни самой RawTable, то есть выходная ссылка будет всегда валидна, так как нельзя вернуть ссылку на удаленную таблицу.

То есть, метод find который возвращает полностью небезопасный "сырой указатель" который может существовать даже после удаления RawTable, и по определению unsafe, превратился полностью в safe. Так как с помощью метода get мы явно привязали жизнь сырого указателя к жизни RawTable. Кроме того мы привязали его не просто к таблице. Мы еще и заблокировали изменения самой RawTable, пока существует на него ссылка. И все это в 10 строк кода (функции get).

Вот так мы и переходим из unsafe в поле safe. Далее уже компилятор проверяет, что ссылка которую мы вернули живет не дальше чем сама структура хеш таблицы, не даст изменить хеш таблицу при наличии действующей ссылки (например вставить новый элемент, что потенциально может привести к аллоцированию нового блока памяти и перевода элементов соответственно в другую область памяти, что автоматический делает висящими все существующие ссылки).

В этом плане все таки компилируемые языки лучше. К них даже статическая линковка не сильно увеличивает размер бинаря

Собственно все ARM, x64, x82 прекрасно поддерживаются Rust. Они входят в Tier 1. У Tier 2 поддержка тоже хорошая (один черт при разработке ядра и драйверов стандартная библиотека не используется). Все остальное это такие редкостные архитектуры, что если надо то будут писать на C. И драйвера не бывают "кроссплатформенными". Бывают скажем "разработанные вручную под разные платформы":-). И понятно никто не будет разрабатывать драйвер для архитектуры на которой работает 1,5 устройств.

Но они никак не помогают при написании асинхронного кода

Information

Rating
Does not participate
Registered
Activity