Argomenti da riga di comando in Rust
Quasi tutti i piccoli progetti che vale la pena costruire per fare pratica (una lista di cose da fare, un contatore di parole) devono ricevere input dalla riga di comando invece di avere i valori scritti fissi nel codice. Questa pagina copre le basi.
Leggere gli argomenti con std::env::args
Sezione intitolata “Leggere gli argomenti con std::env::args”use std::env;
fn main() { let args: Vec<String> = env::args().collect(); println!("{:?}", args);}Se compilassi questo codice in un programma chiamato greet e lo eseguissi così:
./greet AliceVedresti:
["greet", "Alice"]Il primo elemento è sempre il nome del programma stesso: gli argomenti che hai scritto davvero partono dall’indice 1.
Leggere un argomento specifico
Sezione intitolata “Leggere un argomento specifico”use std::env;
fn main() { let args: Vec<String> = env::args().collect();
if args.len() < 2 { println!("Uso: greet <nome>"); return; }
let name = &args[1]; println!("Ciao, {name}!");}Eseguilo con cargo run -- Alice e otterrai:
Ciao, Alice!Eseguilo senza argomenti e vedrai il messaggio d’uso invece di un crash: controllare args.len() prima di usare un indice evita un panic se qualcuno si dimentica di passare qualcosa.
Convertire un argomento in un numero
Sezione intitolata “Convertire un argomento in un numero”Visto che ogni argomento arriva come String, spesso ti servirà .parse() (dalla pagina sulla Conversione di tipo) per trasformarlo in un numero:
use std::env;
fn main() { let args: Vec<String> = env::args().collect();
if args.len() < 2 { println!("Uso: square <numero>"); return; }
match args[1].parse::<i32>() { Ok(n) => println!("{}", n * n), Err(_) => println!("Questo non è un numero valido"), }}Gestire un flag semplice a mano
Sezione intitolata “Gestire un flag semplice a mano”Un flag è un argomento che attiva qualcosa, come --shout. Prima di ricorrere a un crate, è utile vedere come lo gestiresti da solo. Il trucco che rende tutto facile da provare è mettere la logica in una funzione che riceve gli argomenti come slice, &[String]. Così main può passare gli argomenti veri, e tu puoi passare una lista fatta a mano mentre sperimenti:
fn run(args: &[String]) { let mut shout = false; let mut names = Vec::new();
// salta l'indice 0, il nome del programma for arg in &args[1..] { if arg == "--shout" { shout = true; } else { names.push(arg); } }
if names.is_empty() { println!("Uso: greet [--shout] <nome>..."); return; }
for name in names { let line = format!("Ciao, {name}!"); if shout { println!("{}", line.to_uppercase()); } else { println!("{line}"); } }}
fn main() { // In un programma vero scriveresti: // let args: Vec<String> = std::env::args().collect(); // Qui costruiamo la lista a mano, così funziona anche nel Playground. let args = vec![ String::from("greet"), String::from("--shout"), String::from("Ana"), String::from("Ben"), ]; run(&args);}Output:
CIAO, ANA!CIAO, BEN!Alcune cose da notare:
&args[1..]sono tutti gli argomenti tranne il nome del programma. Il flag può comparire ovunque: funziona anchegreet Ana --shout Ben.- Togli
--shoutdalla lista ed eseguilo di nuovo: ottieni i saluti normali. Togli anche i nomi, e ottieni il messaggio d’uso. - Visto che a
runnon importa da dove arriva la sua lista, passare astd::env::args().collect()è una modifica di una riga inmain.
Per uno o due flag va benissimo. Quando vuoi anche le versioni brevi (-s), dei valori dopo un flag (--count 3) e un messaggio --help, il ciclo scritto a mano cresce in fretta. È il momento di passare a clap.
Per qualcosa di più di un paio di argomenti: usa clap
Sezione intitolata “Per qualcosa di più di un paio di argomenti: usa clap”Leggere args a mano per indice diventa scomodo molto in fretta quando ti servono flag (--verbose), valori opzionali o un --help utile. La soluzione standard è il crate clap (documentazione in inglese), che aggiungi con:
cargo add clap --features deriveuse clap::Parser;
#[derive(Parser)]struct Args { name: String,
#[arg(short, long, default_value_t = 1)] count: u32,}
fn main() { let args = Args::parse(); for _ in 0..args.count { println!("Hello, {}!", args.name); }}Così ottieni il parsing degli argomenti, la validazione e un messaggio --help funzionante, tutto generato a partire dalla definizione della struct. Per gli script veloci clap non ti serve, ma per qualsiasi cosa userai davvero più di una volta ti risparmia un sacco di lavoro manuale.
Pratica
Sezione intitolata “Pratica”Il Playground non può passare argomenti veri, quindi entrambi gli esercizi partono da un Vec<String> fatto a mano, identico a quello che ti darebbe env::args().collect(). Sul tuo computer, sostituiscilo con quello vero e prova cargo run -- ....
1. Elenca gli argomenti
Sezione intitolata “1. Elenca gli argomenti”Dato vec!["notes", "add", "compra il latte"] (come String), stampa quanti argomenti ha scritto l’utente (senza contare il nome del programma), poi stampa ciascuno con la sua posizione, partendo da 1.
Suggerimento: il conteggio è args.len() - 1. Un ciclo for i in 1..args.len() ti dà ogni indice dopo il nome del programma.
Mostra la soluzione
fn main() { // fai finta che arrivi da std::env::args().collect() let args = vec![ String::from("notes"), String::from("add"), String::from("compra il latte"), ];
println!("Hai passato {} argomenti", args.len() - 1); for i in 1..args.len() { println!("{i}: {}", args[i]); }}Output:
Hai passato 2 argomenti1: add2: compra il latte"compra il latte" conta come un solo argomento: su una vera riga di comando lo scriveresti tra virgolette (cargo run -- add "compra il latte"), e la shell lo passa come un’unica stringa. L’indice 0 è sempre il nome del programma, ed è per questo che il ciclo parte da 1.
2. Somma i numeri
Sezione intitolata “2. Somma i numeri”Dato vec!["sum", "4", "10", "x", "6"], somma tutti gli argomenti che sono numeri validi e stampa un avviso per quelli che non lo sono. Alla fine stampa il totale.
Suggerimento: scorri &args[1..] e usa match arg.parse::<i32>(), come in Convertire un argomento in un numero. Tieni un let mut total = 0; fuori dal ciclo.
Mostra la soluzione
fn main() { let args = vec![ String::from("sum"), String::from("4"), String::from("10"), String::from("x"), String::from("6"), ];
let mut total = 0; for arg in &args[1..] { match arg.parse::<i32>() { Ok(n) => total += n, Err(_) => println!("Salto '{arg}': non è un numero"), } } println!("Totale: {total}");}Output:
Salto 'x': non è un numeroTotale: 20Ogni argomento arriva come testo, anche "4", quindi ognuno va convertito. Saltare l’input sbagliato con un messaggio è più gentile che andare in crash. Se per il tuo programma ha più senso, puoi anche fermarti al primo argomento sbagliato con return.
Riepilogo
Sezione intitolata “Riepilogo”std::env::args().collect()ti dà unVec<String>con gli argomenti da riga di comando; l’indice 0 è sempre il nome del programma.- Controlla
args.len()prima di usare un indice, così un argomento mancante non manda il programma in panic. .parse()trasforma un argomentoStringin un numero, come altrove.- Metti la gestione degli argomenti in una funzione che riceve
&[String], così puoi provarla con una lista fatta a mano. - Per qualsiasi cosa vada oltre un paio di argomenti semplici, il crate
clapè la scelta standard e collaudata.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Quando chiami env::args().collect(), qual è il primo elemento del Vec che ottieni?
2. Perché controllare args.len() prima di usare un indice su args?
3. Che cosa ti dà il crate clap che leggere args a mano per indice non ti dà?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- Accepting Command Line Arguments — The Rust Book (in inglese): l’inizio del progetto
minigrepdel Book, che legge dalla riga di comando una parola da cercare e un nome di file. std::env::args— documentazione della libreria standard (in inglese): che cosa restituisce esattamenteargs(), e quando va in panic (argomenti che non sono Unicode valido).- Program arguments — Rust by Example (in inglese): un breve esempio, più un seguito su come confrontare gli argomenti con
match. - Command Line Applications in Rust (in inglese): un mini-libro gratuito su come costruire veri strumenti CLI, dal parsing degli argomenti ai test e alla distribuzione.
- Tutorial derive di clap — docs.rs (in inglese): una guida passo passo a flag, opzioni, sottocomandi e validazione con
clap.