Как описано в документации по проекции штифта , гарантия, которую делает Pin
, не обязательно рекурсивна.
Основная гарантия здесь заключается в том, что «Pin<P>
предотвращает определенные значения ( указывается указателями, заключенными в Pin<P>
) от перемещения ". По замыслу, это относится к , в частности, к этим значениям в целом, при этом Pin
не делает никаких заявлений о полях этих значений.
Pin
могло быть разработано иначе, но этот конкретный подход весьма полезен, потому что он позволяет каждому конкретному варианту использования решить для себя, нужно ли ему «структурное» закрепление (когда поле должно быть закреплено само по себе) или «неструктурное» закрепление (где вы можете безопасно перемещать или менять местами поле).
В качестве примера представьте себе значение типа PinMe
, которое необходимо закрепить, и поместите это значение в структуру Wrapper
. Указатели на такие Wrapper
значения должны быть Pin
указателями, чтобы предотвратить перемещение внутреннего PinMe
:
#[pin_project]
struct Wrapper {
#[pin]
pinned: PinMe,
}
fn f(w: Pin<&mut Wrapper>) {
// We cannot move the `Wrapper` that `w` points to, as that would move `w.pinned`.
// All we can do is grab a pinned pointer to the `PinMe`:
let inner: Pin<&mut PinMe> = w.project().pinned;
}
Но если Wrapper
имеет другое поле, совершенно не связанное с PinMe
, существует нет причин не перемещать или менять местами это поле:
#[pin_project]
struct Wrapper {
#[pin]
pinned: PinMe,
counter: i32,
}
fn f(w: Pin<&mut Wrapper>) {
let w = w.project();
let inner: Pin<&mut PinMe> = w.pinned;
let counter: &mut i32 = w.counter;
// These sorts of operations do not affect the `PinMe`:
*counter += 3;
mem::replace(counter, 5);
}
Выбор структурного или неструктурного закрепления полностью зависит от инвариантов, которые вам необходимо соблюдать. Если field_b
необходимо оставить рядом с field_a
, добавьте к нему #[pin]
. Но если это не то, что нужно вашему типу Demo
, вы можете не указывать его, что дает меньше гарантий, но все еще безопасно.
Изменить: Кроме того, это применимо, даже если это дополнительное поле не реализует Unpin
, пока ничто не создало Pin
, указывающее прямо на него. Например:
#[pin_project]
struct Wrapper<T> {
#[pin]
pinned: PinMe,
// We know nothing about this type except that it is `Sized`.
// Thus, we cannot assume it implements `Unpin`.
counter: T,
}
fn f<T>(w: Pin<&mut Wrapper<T>>, other: T) {
let w = w.project();
let inner: Pin<&mut PinMe> = w.pinned;
let counter: &mut T = w.counter;
// This is still okay:
mem::replace(counter, other);
}