I generics sono degli strumenti usati in Rust per potere gestire diversi tipi di dato diverso. Sono molto utili perché capiterà spesso di implementare la stessa funzione per diversi tipi di dato.
Rust fa uso dei generici in Option. Infatti, non importa il tipo di dato che usiamo, Rust si preoccupa solo di vedere se l’istanza creata ha un valore oppure no.
enum Option<T> {
Some(T),
None,
}
Possiamo anche gestire dati che hanno uno o più tratti in comune, come PartialOrd, Clone, Debug e Display usando la direttiva #[derive()].
Possiamo infine implementare i generics su una struttura, inserendo il simbolo prima e dopo il nome dell’implementazione.
#[derive(Debug)]
struct Example<T>;
impl<T> Example<T> {
//Inseriamo il codice
}
La copia dei file con i generics
Supponiamo di volere creare una funzione che copia uno o più file. In questo caso non importa il tipo e il formato, l’importante è che possono essere copiati. Ovviamente se lavoriamo con dei tipi di dato che rappresentano i file è importante che venga implementato il relativo trait con #[derive()]. In questo caso è necessario implementare in modo automatico il trait Clone.
Iniziamo creando una funzione che accetta come parametro un array che può contenere soltanto i tipi di dato che possono essere copiati: devono avere il trait Clone, la quale crea un nuovo valore con un nuovo proprietario. Usiamo i simboli < > dopo il nome della funzione e prima di passare gli argomenti per inserire i generics. Il tipo di ritorno riporta un vettore di generics perché abbiamo bisogno di un tipo di dato dinamico per ricevere le varie copie e gestirle.
fn create_copy<T: Clone>(list_file: &[T]) -> Vec<T> {
}
Creiamo all’interno della funzione una vettore mutabile e tramite un ciclo for estrapoliamo i singoli elementi della lista e inseriamo il loro clone nel vettore. Infine ritorniamo il vettore.
fn create_copy<T: Clone>(list_file: &[T]) -> Vec<T> {
let mut new_list = Vec::new();
for file in list_file {
new_list.push(file.clone());
}
new_list
}
Grazie a questa funzione abbiamo creato un comando che potrebbe copiare elementi dentro un archivio ma anche elementi contenuti in una lista dopo che noi abbiamo selezionato diversi elementi. Sotto un esempio con un semplice array statico.
fn main() {
let zip = [
"file.exe",
"file.odt",
"file.png"
];
let zip_copy = create_copy(&zip);
println!("Elements in zip: {:?}", zip);
println!("Elements in zip copy: {:?}", zip_copy);
}
fn create_copy<T: Clone>(list_file: &[T]) -> Vec<T> {
let mut new_list = Vec::new();
for file in list_file {
new_list.push(file.clone());
}
new_list
}