Найти в Дзене
Ржавый код

Заметки о Rust - Unique and NonNull

`Unique<T>` - это тип указателя в Rust, который обычно используется внутри Rust для представления уникальной семантики владения и полезен для построения абстракций, таких как `Box<T>`, `Vec<T>`, `String` и `HashMap<K, V>`. В стандартной библиотеке объявляется в `core/src/ptr/unique.rs` как: `Unique<T>` - это ненулевой ковариантный уникальный указатель. Вот что означают эти термины: Такое сочетание свойств позволяет Rust делать определенные допущения, позволяющие оптимизировать код. Например, поскольку указатели `Unique<T>` не имеют значения `NULL` и уникальны, оптимизатор Rust может предположить, что переопределение `Unique<T>` всегда безопасно и что указатель не будет изменен или перемещен какой-либо другой частью кода. Обратите внимание, что `Unique<T>` является внутренней детализацией реализации стандартной библиотеки Rust. Это не тип, который обычно используется непосредственно в собственном коде. Вместо этого можно использовать такие типы, как `Box<T>`, `Vec<T>` и т.д., которые со
Оглавление

Unique

`Unique<T>` - это тип указателя в Rust, который обычно используется внутри Rust для представления уникальной семантики владения и полезен для построения абстракций, таких как `Box<T>`, `Vec<T>`, `String` и `HashMap<K, V>`.

В стандартной библиотеке объявляется в `core/src/ptr/unique.rs` как:

-2

`Unique<T>` - это ненулевой ковариантный уникальный указатель. Вот что означают эти термины:

  • Это гарантированно никогда не будет NULL.
  • Ковариантный: это свойство, которое позволяет использовать его с подтипами и супертипами. В Rust ковариация `Unique<T>` используется, например, для обеспечения ковариантности `Box<T>` с `T`.
  • Уникальный: означает, что есть только один владелец.

Такое сочетание свойств позволяет Rust делать определенные допущения, позволяющие оптимизировать код. Например, поскольку указатели `Unique<T>` не имеют значения `NULL` и уникальны, оптимизатор Rust может предположить, что переопределение `Unique<T>` всегда безопасно и что указатель не будет изменен или перемещен какой-либо другой частью кода.

Обратите внимание, что `Unique<T>` является внутренней детализацией реализации стандартной библиотеки Rust. Это не тип, который обычно используется непосредственно в собственном коде. Вместо этого можно использовать такие типы, как `Box<T>`, `Vec<T>` и т.д., которые создаются с использованием `Unique` за кулисами.

Например, `Box<T>` объявляется в стандартной библиотеке в файле `alloc/src/boxed.rs` как:

-3

PhantomData

Как показано выше, `Unique<T>` имеет поле `_marker` типа `PhantomData<T>`.

`PhantomData<T>` в Rust - этот тип используется, чтобы указать, что дженерик тип `T` - часть структуры данных, даже если `T` не используется в структуре данных.

`PhantomData<T>` играет важную роль в способности компилятора Rust понимать владение, заимствование и время жизни, и это важно при создании сложных структур данных или при работе с необработанными указателями.

Теперь `Unique<T>` обычно используется с `PhantomData`, поскольку сам `Unique<T>` не «владеет» своим указателем в системе типов Rust. Фактическое владение часто выражается с помощью `PhantomData`.

В объявлении `Unique<T>` структуры `PhantomData<T>` выражает, что он «владеет» `T`, даже если `T` фактически не используется в структуре. Это говорит компилятору Rust, что при удалении `Unique<T>` он может удалить `T`, поэтому он не должен позволять использовать `T` впоследствии.

Без `PhantomData<T>` система типов Rust не поймет, что `Unique<T>` владеет `T`, и это потенциально может привести к неопределенному поведению.

Таким образом, `PhantomData<T>` и `Unique<T>` часто используются вместе в Rust для выражения сложных отношений владения, которые система типов Rust не может выразить самостоятельно.

NonNull

Кроме того, `Unique<T>` не хранит необработанный указатель напрямую. Вместо этого он является указателем поля типа `NonNull<T>`.

В Rust значение `NonNull<T>` является оберткой необработанного указателя, которое гарантированно не равно NULL. Это по существу то же самое, что и `*mut T`, но с добавленным инвариантом, что он не является нулевым.

Необработанные указатели в Rust обычно используются при взаимодействии с кодом `C` или при построении небезопасных абстракций Rust. Однако указатели `NULL` часто могут вызывать ошибки и сбои, поэтому `NonNull<T>` предоставляется как способ гарантировать, что необработанный указатель никогда не будет `null`.

Это дает некоторые гарантии безопасности в том смысле, что перед использованием не нужно проверять значение `NULL`. Но имейте в виду, что, несмотря на то, что оно не может быть нулевым, использование `NonNull<T>` по-прежнему небезопасно, поскольку оно не дает вам никаких гарантий заимствования или срока службы, которые ссылаются (`&T` и `&mut T`).

Ниже приведен пример использования `NonNull<T>`:

-4

В этом примере `NonNull::new` используется для создания нового `NonNull<T>`. Затем `NonNull::as_ptr` используется для получения необработанного указателя, который можно отменить и изменить в `unsafe` блоке.

Статья на rusty-code.ru