Rust offre tipi avanzati che permettono di modellare dati complessi in modo elegante e sicuro. Le struct sono perfette per raggruppare dati correlati, mentre gli enum consentono di rappresentare varianti e stati. Con pattern matching, Rust fornisce un potente strumento per gestire questi tipi in modo chiaro ed espressivo. Infine, tipi speciali come Option
e Result
aiutano a gestire casi di valore mancante ed errori in modo sicuro.
In questa lezione, esploreremo questi concetti con esempi pratici.
Le struct permettono di raggruppare più valori sotto un unico tipo. Ci sono tre tipi principali di struct in Rust:
Una struct classica ha campi nominati:
struct Persona {
nome: String,
eta: u32,
}
fn main() {
let persona = Persona {
nome: String::from("Alice"),
eta: 30,
};
println!("Nome: {}, Età: {}", persona.nome, persona.eta);
}
Le struct a tuple non hanno nomi di campo, ma utilizzano posizioni:
struct Punto(i32, i32);
fn main() {
let p = Punto(10, 20);
println!("Punto: ({}, {})", p.0, p.1);
}
Le struct unitarie non hanno campi. Vengono spesso utilizzate per implementare trait.
struct Unitaria;
fn main() {
let _u = Unitaria;
}
Gli enum in Rust sono ideali per rappresentare un insieme di varianti. Ogni variante può contenere dati aggiuntivi.
enum Stagione {
Primavera,
Estate,
Autunno,
Inverno,
}
fn main() {
let stagione_corrente = Stagione::Estate;
match stagione_corrente {
Stagione::Primavera => println!("È primavera!"),
Stagione::Estate => println!("È estate!"),
Stagione::Autunno => println!("È autunno!"),
Stagione::Inverno => println!("È inverno!"),
}
}
Ogni variante può contenere dati:
enum Messaggio {
Testo(String),
Coordinata { x: i32, y: i32 },
Numero(i32),
}
fn main() {
let messaggio = Messaggio::Coordinata { x: 10, y: 20 };
match messaggio {
Messaggio::Testo(testo) => println!("Messaggio: {}", testo),
Messaggio::Coordinata { x, y } => println!("Coordinate: ({}, {})", x, y),
Messaggio::Numero(num) => println!("Numero: {}", num),
}
}
match
Il pattern matching in Rust consente di verificare e destrutturare valori complessi in modo conciso e leggibile.
enum Stato {
Online,
Offline,
InRiparazione,
}
fn stato_dispositivo(stato: Stato) {
match stato {
Stato::Online => println!("Il dispositivo è online."),
Stato::Offline => println!("Il dispositivo è offline."),
Stato::InRiparazione => println!("Il dispositivo è in riparazione."),
}
}
fn main() {
let stato = Stato::Online;
stato_dispositivo(stato);
}
_
per Gestire Casi Non Specificatifn valuta(numero: i32) {
match numero {
1 => println!("Uno"),
2 => println!("Due"),
_ => println!("Altro numero"),
}
}
fn main() {
valuta(5);
}
Option
e Result
Rust non utilizza null, ma fornisce i tipi Option
e Result
per rappresentare casi di valore mancante ed errori.
Option
per Valori MancantiIl tipo Option
può essere Some(T)
per un valore presente o None
per un valore mancante.
fn trova_valore(numero: i32) -> Option {
if numero > 0 {
Some(numero * 2)
} else {
None
}
}
fn main() {
match trova_valore(5) {
Some(valore) => println!("Valore trovato: {}", valore),
None => println!("Nessun valore trovato."),
}
}
Result
per Gestire ErroriResult
è utilizzato per operazioni che possono fallire. Può essere Ok(T)
per un risultato valido o Err(E)
per un errore.
fn dividi(a: i32, b: i32) -> Result {
if b == 0 {
Err(String::from("Errore: divisione per zero"))
} else {
Ok(a / b)
}
}
fn main() {
match dividi(10, 0) {
Ok(risultato) => println!("Risultato: {}", risultato),
Err(errore) => println!("{}", errore),
}
}
Rettangolo
con campi altezza
e larghezza
, e implementa una funzione per calcolare l’area.Operazione
con varianti per addizione, sottrazione e moltiplicazione, e utilizza match
per eseguire l'operazione corrispondente.Option
per scrivere una funzione che restituisce il quadrato di un numero positivo o None
se il numero è negativo.Result
per leggere un file e gestire possibili errori.Le struct e gli enum in Rust ti permettono di modellare i dati in modo preciso ed espressivo, mentre pattern matching e tipi come Option
e Result
garantiscono un controllo efficace sui flussi di dati e sugli errori. Questi strumenti, insieme, ti aiuteranno a scrivere codice robusto, sicuro e facilmente manutenibile. Nel prossimo articolo esploreremo argomenti come Vettori, Array e Iteratori. Continua a esercitarti con gli esempi forniti e padroneggia questi concetti avanzati di Rust!