În modelul de memorie din Rust, toate valorile sunt implicit mutabile în memorie (Movable): compilatorul poate muta o structură dintr-un registru pe stivă sau între două locații de memorie printr-o simplă copiere binară rapidă (memcpy). Această mutare este complet sigură pentru tipurile standard, însă devine fatală pentru structurile auto-referențiale (unde un câmp conține un pointer către un alt câmp din interiorul aceleiași structuri).
Dacă o structură auto-referențială este mutată în altă zonă de memorie, pointerul intern va continua să indice către vechea adresă invalidă (provocând un Dangling Pointer). Deoarece fiecare funcție async este transformată de compilator într-o mașină de stări auto-referențială, Rust introduce tipul std::pin::Pin pentru a ancora obiectele la o adresă fizică imuabilă.
use std::marker::PhantomPinned;
use std::pin::Pin;
// Structură ce nu poate fi mutată în memorie odată inițializată:
struct NodAutoReferential {
valoare: String,
// Pointer către propriul câmp 'valoare':
auto_pointer: *const String,
// PhantomPinned anulează automat implementarea implicită a trait-ului Unpin:
_ancora: PhantomPinned,
}
impl NodAutoReferential {
fn new(text: &str) -> Self {
NodAutoReferential {
valoare: String::from(text),
auto_pointer: std::ptr::null(),
_ancora: PhantomPinned,
}
}
fn init(self: Pin<&mut Self>) {
let adresa_valoare = &self.valoare as *const String;
// Modificare sigură prin unsafe deoarece obiectul este deja anulat (pinned):
unsafe {
let pointer_mutabil = self.get_unchecked_mut();
pointer_mutabil.auto_pointer = adresa_valoare;
}
}
}
fn main() {
// Alocăm structura pe heap într-o cutie fixată (Pinned Box):
let mut instanta_ancorata = Box::pin(NodAutoReferential::new("Date critice"));
instanta_ancorata.as_mut().init();
// Încercarea de a face std::mem::swap pe 'instanta_ancorata'
// generează o eroare directă de compilare: trait-ul Unpin nu este implementat!
}
Diferența dintre Unpin și !Unpin
Unpin(Implicit): Aproape toate tipurile din Rust (i32,String, vectori) implementează automatUnpin. Pentru acestea,Pin<&mut T>este doar un ambalaj transparent și pot fi mutate fără riscuri.!Unpin(Opt-out): Tipurile care conținPhantomPinnedsau stările interne generate de blocuriasyncrenunță laUnpin. Compilatorul garantează contractual că memoria de sub pointer nu va fi niciodată mutată până la finalul duratei sale de viață.