Metodi generici
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 25 di 61.
Una struct generica può contenere qualsiasi tipo, ma non è molto utile senza metodi per interagire con i suoi dati. Per definire metodi per una struct generica, devi usare una sintassi speciale nel blocco impl.
La chiave è dichiarare il parametro generico sullo stesso impl:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Nota impl<T> prima di Wrapper<T>. Questo indica a Rust che T è un parametro di tipo generico per l'intero blocco di implementazione. Senza questa dichiarazione, Rust cercherebbe un tipo concreto chiamato T e non riuscirebbe a trovarlo.
Il metodo get restituisce &T: un riferimento al tipo contenuto nel wrapper. Funziona sia che T sia un intero, una stringa o qualsiasi altro tipo:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
La stessa definizione di metodo funziona per entrambi, perché il generico T si adatta a ciascun tipo concreto in fase di compilazione.
Sfida
FacileEstenderai il tuo contenitore generico con dei metodi! Costruirai una struct Box (da non confondere con la Box standard di Rust) che può contenere qualsiasi tipo e fornisce metodi per interagire con il suo contenuto.
Organizzerai il codice in due file:
mybox.rs: Definisci una struct generica pubblica chiamataMyBox<T>con un campo privatocontentsdi tipoT. Implementa dei metodi per questa struct:- Una funzione associata
newche crea una nuovaMyBoxcon il valore specificato - Un metodo
peekche restituisce un riferimento al contenuto (usando&self) - Un metodo
replaceche accetta un nuovo valore e sostituisce il contenuto attuale (usando&mut self)
- Una funzione associata
main.rs: Importa il tuo modulo e mostra il funzionamento dei metodi generici con tipi diversi. Creerai delle box, ne esaminerai il contenuto e sostituirai i valori per mostrare i metodi in azione.
Ricorda la sintassi fondamentale per implementare metodi su una struct generica: devi usare impl<T> prima di MyBox<T> per indicare a Rust che T è un parametro generico per l'intero blocco di implementazione.
Nel tuo file principale, mostra MyBox:
- Creando una box con un intero (il primo input, analizzato come
i32) - Esaminandone il contenuto e stampando il valore
- Sostituendo il contenuto con un nuovo intero (il secondo input, analizzato come
i32) - Esaminandolo di nuovo per mostrare il valore aggiornato
- Creando una seconda box con una stringa (il terzo input)
- Esaminando il contenuto della box con la stringa
L'output deve rispettare questo formato:
Integer box contains: {value}
After replace: {value}
String box contains: {value}Per esempio, con gli input 10, 25 e Rust:
Integer box contains: 10
After replace: 25
String box contains: RustRiceverai tre input: un intero iniziale, un intero sostitutivo e una stringa.
Provalo tu
mod mybox;
use mybox::MyBox;
fn main() {
// Leggi gli input
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Crea un MyBox con il numero intero iniziale
// TODO: Controlla il suo contenuto e stampa: "Integer box contains: {value}"
// TODO: Sostituisci il contenuto con il numero intero sostitutivo
// TODO: Controlla di nuovo e stampa: "After replace: {value}"
// TODO: Crea un secondo MyBox con il valore della stringa
// TODO: Controlla il contenuto del box della stringa e stampa: "String box contains: {value}"
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online