Puntatori Intelligenti
Un puntatore è un concetto generale che rappresenta una variabile che contiene
un indirizzo in memoria. Questo indirizzo fa riferimento, o “punta a”, altri
dati. Il tipo più comune di puntatore in Rust è un reference, come hai
imparato nel Capitolo 4. I reference sono indicati dal simbolo &
e prendono
in prestito il valore a cui puntano. Non hanno capacità speciali oltre al
riferimento ai dati, e non hanno costi prestazionali aggiuntivi (overhead).
I puntatori intelligenti (smart pointers), d’altra parte, sono strutture dati che si comportano come un puntatore ma hanno anche metadati e capacità aggiuntive. Il concetto di puntatori intelligenti non è esclusivo di Rust: i puntatori intelligenti hanno avuto origine in C++ ed esistono anche in altri linguaggi. Rust ha una varietà di puntatori intelligenti definiti nella libreria standard che forniscono funzionalità che vanno oltre quelle fornite dai reference. Per esplorare il concetto generale, esamineremo un paio di esempi diversi di puntatori intelligenti, incluso un tipo di puntatore intelligente con conteggio dei riferimenti. Questo puntatore consente ai dati di avere più proprietari tenendo traccia del loro numero e, quando non ne rimane nessuno, de-allocare i dati.
Rust, con il suo concetto di ownership e borrowing, presenta un’ulteriore differenza tra reference e i puntatori intelligenti: mentre i reference prendono solo in prestito dati, in molti casi i puntatori intelligenti posseggono i dati a cui puntano.
I puntatori intelligenti sono solitamente implementati tramite struct. A
differenza di una normale struct, i puntatori intelligenti implementano i
trait Deref
e Drop
. Il trait Deref
consente a un’istanza della
struct del puntatore intelligente di comportarsi come un reference in modo
da poter scrivere codice che funzioni sia con reference che con puntatori
intelligenti. Il trait Drop
consente di personalizzare il codice che viene
eseguito quando un’istanza del puntatore intelligente esce dallo scope. In
questo capitolo, discuteremo entrambi questi trait e dimostreremo perché sono
importanti per i puntatori intelligenti.
Dato che il puntatore intelligente è un design generale utilizzato frequentemente in Rust, questo capitolo non tratterà tutti i puntatori intelligenti esistenti. Molte librerie hanno i propri puntatori intelligenti, ed è anche possibile scriverne di propri. Tratteremo i più comuni nella libreria standard:
Box<T>
, per l’allocazione di valori nell’heapRc<T>
, un type di conteggio dei reference che consente la ownership multiplaRef<T>
eRefMut<T>
, accessibili tramiteRefCell<T>
, type che applicano le regole di prestito durante l’esecuzione anziché in fase di compilazione
Inoltre, tratteremo il modello di mutabilità interna, in cui un type immutabile espone un’API per la mutazione di un valore interno. Discuteremo anche dei cicli di riferimento e di come possono causare perdite di memoria e come prevenirle.
Cominciamo!