Rust è un linguaggio di programmazione moderno che combina prestazioni elevate con sicurezza della memoria. Uno dei concetti fondamentali in Rust è quello dei struct, che permettono di creare tipi di dati personalizzati per organizzare e gestire informazioni complesse. In questo articolo, esploreremo cosa sono gli struct, come si dichiarano, come si utilizzano e alcune delle loro caratteristiche avanzate.
1. Cosa sono gli Struct?
Gli struct (abbreviazione di “structure”) sono tipi di dati personalizzati che permettono di raggruppare più valori sotto un unico nome. Ogni valore all’interno di uno struct è chiamato campo, e ogni campo ha un nome e un tipo. Gli struct sono simili alle classi in altri linguaggi, ma in Rust sono più leggeri e non supportano l’ereditarietà.
1.1. Dichiarazione di uno Struct
Per dichiarare uno struct, si utilizza la parola chiave struct
seguita dal nome dello struct e dai suoi campi. Ecco un esempio:
struct Persona {
nome: String,
eta: u8,
attivo: bool,
}
In questo esempio, abbiamo definito uno struct chiamato Persona
con tre campi: nome
(di tipo String
), eta
(di tipo u8
) e attivo
(di tipo bool
).
1.2. Creazione di un’Istanza di Struct
Per creare un’istanza di uno struct, si utilizza la sintassi seguente:
let persona1 = Persona {
nome: String::from("Alice"),
eta: 30,
attivo: true,
};
In questo caso, persona1
è un’istanza dello struct Persona
con i valori specificati per ciascun campo.
1.3. Accesso ai Campi di uno Struct
Per accedere ai campi di uno struct, si utilizza la notazione del punto (.
):
println!("Nome: {}", persona1.nome);
println!("Età: {}", persona1.eta);
println!("Attivo: {}", persona1.attivo);
Output:
Nome: Alice
Età: 30
Attivo: true
2. Struct Mutabili
Per modificare i campi di uno struct, l’istanza deve essere dichiarata come mutabile:
let mut persona1 = Persona {
nome: String::from("Alice"),
eta: 30,
attivo: true,
};
persona1.eta = 31; // Modifica del campo "eta"
persona1.attivo = false; // Modifica del campo "attivo"
Se l’istanza non è dichiarata come mutabile, non sarà possibile modificare i suoi campi.
3. Struct con Campi Opzionali
In Rust, non esiste un concetto di “campi opzionali” direttamente negli struct. Tuttavia, è possibile utilizzare il tipo Option<T>
per rappresentare campi che possono essere assenti:
struct Persona {
nome: String,
eta: u8,
indirizzo: Option<String>,
}
let persona1 = Persona {
nome: String::from("Bob"),
eta: 25,
indirizzo: Some(String::from("Via Roma 123")),
};
let persona2 = Persona {
nome: String::from("Charlie"),
eta: 22,
indirizzo: None,
};
In questo esempio, il campo indirizzo
è opzionale e può contenere un valore di tipo String
o None
.
4. Metodi e Funzioni Associate
Gli struct in Rust possono avere metodi e funzioni associate, che sono definiti all’interno di un blocco impl
.
4.1. Definizione di Metodi
I metodi sono funzioni che operano su un’istanza di uno struct. Il primo parametro di un metodo è sempre &self
(riferimento immutabile) o &mut self
(riferimento mutabile). Ecco un esempio:
impl Persona {
fn saluta(&self) {
println!("Ciao, mi chiamo {}!", self.nome);
}
fn compie_anni(&mut self) {
self.eta += 1;
println!("Ora ho {} anni!", self.eta);
}
}
let mut persona1 = Persona {
nome: String::from("Alice"),
eta: 30,
attivo: true,
};
persona1.saluta(); // Output: Ciao, mi chiamo Alice!
persona1.compie_anni(); // Output: Ora ho 31 anni!
4.2. Funzioni Associate
Le funzioni associate sono simili ai metodi, ma non prendono self
come parametro. Sono spesso utilizzate come costruttori. Ecco un esempio:
impl Persona {
fn nuova(nome: String, eta: u8) -> Persona {
Persona {
nome,
eta,
attivo: true,
}
}
}
let persona2 = Persona::nuova(String::from("Bob"), 25);
In questo caso, nuova
è una funzione associata che crea una nuova istanza di Persona
.
5. Struct Tuple
Rust supporta anche gli struct tuple, che sono simili agli struct tradizionali ma senza nomi per i campi. I campi sono identificati solo dalla loro posizione. Ecco un esempio:
struct Colore(u8, u8, u8);
let rosso = Colore(255, 0, 0);
println!("Rosso: {}, {}, {}", rosso.0, rosso.1, rosso.2);
Output:
Rosso: 255, 0, 0
6. Struct Unitari
Gli struct unitari sono struct senza campi. Sono utili per implementare tratti o per creare tipi marker. Ecco un esempio:
struct Marker;
let m = Marker;
7. Pattern Matching con Struct
Rust supporta il pattern matching sugli struct, che permette di estrarre i valori dei campi in modo conciso. Ecco un esempio:
let persona1 = Persona {
nome: String::from("Alice"),
eta: 30,
attivo: true,
};
match persona1 {
Persona { nome, eta, attivo } => {
println!("Nome: {}, Età: {}, Attivo: {}", nome, eta, attivo);
}
}
Output:
Nome: Alice, Età: 30, Attivo: true
8. Conclusioni
Gli struct sono uno strumento potente in Rust per organizzare e gestire dati complessi. Con questa guida, hai imparato come dichiarare, creare e utilizzare struct, oltre a esplorare funzionalità avanzate come metodi, funzioni associate e pattern matching. Gli struct sono fondamentali per scrivere codice Rust modulare e sicuro, e ora sei pronto per utilizzarli nei tuoi progetti!