Трейт Unpin
Трейт Unpin - это маркерный трейт, который сообщает компилятору,
что значение типа можно безопасно перемещать в памяти, даже если оно
было закреплено с помощью Pin. По умолчанию большинство типов
в Rust автоматически реализуют Unpin. Трейт не имеет методов
и не принимает параметров - это чисто маркерное соглашение о свойствах
типа.
Типы, которые не реализуют Unpin, обычно содержат
самореферентные структуры или используются в асинхронном коде,
где перемещение в памяти может привести к повреждению данных.
Если тип реализует Unpin, то для него можно безопасно
использовать методы Pin::new и получать изменяемый доступ
к закреплённому значению.
Синтаксис
impl Unpin for MyType { }
Автоматическая реализация для обычных типов:
struct MyStruct
{
field: i32,
}
// MyStruct автоматически реализует Unpin
Пример
Давайте проверим, реализует ли обычная структура трейт Unpin:
use std::pin::Pin;
struct MyStruct
{
value: i32,
}
fn main()
{
let res = is_unpin::<MyStruct>();
println!("{}", res);
}
fn is_unpin<T: Unpin>() -> bool
{
true
}
Результат выполнения кода:
true
Пример
Давайте создадим тип, который не реализует Unpin,
используя PhantomPinned, и проверим это:
use std::marker::PhantomPinned;
struct NotUnpin
{
value: i32,
_pin: PhantomPinned,
}
fn main()
{
let res = is_unpin::<NotUnpin>();
println!("{}", res);
}
fn is_unpin<T: Unpin>() -> bool
{
true
}
Этот код не скомпилируется, потому что NotUnpin
не реализует Unpin из-за поля PhantomPinned.
Компилятор выдаст ошибку о невыполненной границе трейта.
Пример
Давайте проверим, можно ли распаковать закреплённое значение
типа, реализующего Unpin:
use std::pin::Pin;
fn main()
{
let value = 12345;
let pinned = Box::pin(value);
let res = Pin::into_inner(pinned);
println!("{}", res);
}
Результат выполнения кода:
12345