Indice
Curiosità e appunti vari sul linguaggio Rust
Autore: Fabio Di Matteo
Ultima revisione: 05/04/2026 19:24
Provenendo da altri linguaggi ho avuto qualche difficoltà ad abituarmi alla sintassi e buone pratiche incoraggiate dal Rust. Metto qualche appunto.
Blocco try/catch
In Rust il try/catch non esiste. Abbiamo i Result. Ecco alcune soluzioni al caso:
Esempio base
Creo una funzione che costruisce un errore e poi la uso in un blocco match:
use std::io; fn divisione(a: i16, b: i16) -> Result<i16, io::Error> { if b == 0 { // Creiamo un errore I/O semplice per il caso di divisione per zero return Err(io::Error::new(io::ErrorKind::Other, "divisione per zero")); } Ok(a / b) } fn main() { match divisione(16, 0) { Ok(r) => { println!("Risultato: {}", r); } Err(err) => { eprintln!("Errore: {}", err); } } println!("Questo viene dopo."); }
Altro esempio. Qui non restituisco un tipo di errore come errore, ma solo una stringa. Questo puo' essere piu' giusto nella validazione dei campi inseriti. In quanto potrebbe essere fuorviante stimolare un'errore io, altro.
fn maggiorenne(eta: i16) -> Result<bool, String> { if eta < 18 { return Err("Non sei maggiorenne".into()); } Ok(true) } fn main() { match maggiorenne(4) { Ok(m) => { println!( "Perfetto, sei maggiorenne. Dunque la funzione restituisce {}", m ); } Err(e) => { println!("Errore: {}", e); } } println!("Questo viene dopo. E fa parte del programma principale."); }
Con match su una funzione della libreria standard
use std::fs::File; fn main() { match File::open("hello.txt") { Ok(f) => { println!("File aperto correttamente."); drop(f); } Err(err) => { eprintln!("Errore aprendo file: {}", err); return; } }; println!("Qui siamo dopo.") }
Con un semplice if
if let Ok(mut f) = File::open("a.txt") { /* successo */ } else { /* gestione fallimento */ }
Con is_ok/ is_err
let r = File::open("foo.txt"); if r.is_err() { eprintln!("Errore aprendo file: {:?}", r.err().unwrap()); } else { let mut f = r.unwrap(); // usa f }
Crosscompilare applicazioni
Alcuni comandi utili nella crosscompilazione per altre architetture. Per installare i vari pacchetti useremo rustup
Elencare i target installabili e installarne uno
Con il seguente comando vedremo i target installabili e quelli già installati.
rustup target list
E' possibile installarne uno con
rustup target add <target di mia scelta>
Per esempio:
rustup target add x86_64-pc-windows-gnu
In questo esempio installo il target per le crosscompilazioni su windows con mingw64. Quindi è richiesto in questo caso l'installazione di mingw .
Compilare il nostro progetto per target prescelto
Se vogliamo compilare il nostro progetto possiamo farlo con il seguente comando:
cargo build --target=<target di mia scelta>
come per esempio:
cargo build --target=x86_64-unknown-linux-musl
Quest'ultimo esempio mi genera un eseguibile statico per linux x86_64 grazie alla libreria musl.
Note sulla crosscompilazione per arm64
E' necessario installare il compilatore gcc per arm64. Su Arch linux:
sudo pacman -S aarch64-linux-gnu-gcc aarch64-linux-gnu-binutils
e impostare alcune variabili d'ambiente per constringere rust a usare il linker di arm64:
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
Crosscopilare con :
cargo build --target=aarch64-unknown-linux-gnu
Crosscompilare staticamente con musl per aarch64?
impostiamo queste variabili d'ambiente:
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc export CC_aarch64_unknown_linux_musl=aarch64-linux-gnu-gcc
e compiliamo con :
cargo build --target=aarch64-unknown-linux-musl
assicurandoci prima di aver installato il target in sopraindicato.
Le classi
Un esempio minimo.
struct Persona { id: i16, name: String, surname: String, } impl Persona { fn new() -> Self { return Self { id: 0, name: "".into(), surname: "".into(), }; } fn set(&mut self, id: i16, name: String, surname: String) { self.id = id; self.name = name; self.surname = surname; } } fn main() { let mut p = Persona::new(); p.set(1, "Fabio".into(), "Di Matteo".into()); println!("{} {} {}", p.id, p.name, p.surname); }
Versione con l'aggiunta di un metodo “getter”:
struct Persona { id: i16, name: String, surname: String, } impl Persona { fn new() -> Self { return Self { id: 0, name: "".into(), surname: "".into(), }; } fn set(&mut self, id: i16, name: String, surname: String) { self.id = id; self.name = name; self.surname = surname; } fn get(&self, op: String) -> String { if op == "name" { return self.name.clone(); } else if op == "surname" { return self.surname.clone(); } else { return self.id.to_string(); } } } fn main() { let mut p = Persona::new(); p.set(1, "Fabio".into(), "Di Matteo".into()); let nome = p.get("name".into()); let cognome = p.get("surname".into()); let id = p.get("id".into()); println!("{} {} {}", id, nome, cognome); }
Sviluppo di programmi dotatati di gui
Di seguito le mmie esperienze:
