Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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’heap
  • Rc<T>, un type di conteggio dei reference che consente la ownership multipla
  • Ref<T> e RefMut<T>, accessibili tramite RefCell<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!