Il tutorial di Rust non spiega come prendere parametri dalla riga di comando. fn main()
viene mostrato solo con un elenco di parametri vuoto in tutti gli esempi.
Qual è il modo corretto di accedere ai parametri della riga di comando main
?
Il tutorial di Rust non spiega come prendere parametri dalla riga di comando. fn main()
viene mostrato solo con un elenco di parametri vuoto in tutti gli esempi.
Qual è il modo corretto di accedere ai parametri della riga di comando main
?
Risposte:
È possibile accedere agli argomenti della riga di comando utilizzando le funzioni std::env::args
o std::env::args_os
. Entrambe le funzioni restituiscono un iteratore sugli argomenti. Il primo scorre sopra String
s (che sono facili da lavorare) ma si fa prendere dal panico se uno degli argomenti non è unicode valido. Quest'ultimo scorre su se OsString
non si fa mai prendere dal panico.
Si noti che il primo elemento dell'iteratore è il nome del programma stesso (questa è una convenzione in tutti i principali sistemi operativi), quindi il primo argomento è in realtà il secondo elemento iterato.
Un modo semplice per gestire il risultato di args
è convertirlo in un Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
È possibile utilizzare l'intero toolbox iteratore standard per lavorare con questi argomenti. Ad esempio, per recuperare solo il primo argomento:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Puoi trovare le librerie su crates.io per analizzare gli argomenti della riga di comando:
Docopt è disponibile anche per Rust, che genera un parser per te da una stringa di utilizzo. Come bonus in Rust, una macro può essere utilizzata per generare automaticamente la struttura ed eseguire la decodifica basata sul tipo:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
E puoi ottenere gli argomenti con:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
Il file README e la documentazione contengono numerosi esempi di lavoro completi.
Disclaimer: sono uno degli autori di questa biblioteca.
Rust ha un getopt
argomento CLI in stile che analizza nella cassa getopts .
Per me, getopts è sempre sembrato di livello troppo basso e docopt.rs era troppo magico. Voglio qualcosa di esplicito e diretto che fornisca comunque tutte le funzionalità se ne ho bisogno.
Questo è dove clap-rs è utile.
Sembra un po 'argparse da Python. Ecco un esempio di come appare:
let matches = App::new("myapp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(Arg::with_name("CONFIG")
.short("c")
.long("config")
.help("Sets a custom config file")
.takes_value(true))
.arg(Arg::with_name("INPUT")
.help("Sets the input file to use")
.required(true)
.index(1))
.arg(Arg::with_name("debug")
.short("d")
.multiple(true)
.help("Sets the level of debugging information"))
.get_matches();
Puoi accedere ai tuoi parametri in questo modo:
println!("Using input file: {}", matches.value_of("INPUT").unwrap());
// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);
(Copiato dalla documentazione ufficiale )
A partire dalla versione 0.8 / 0.9, il percorso corretto per la funzione args () sarebbe ::std::os::args
, cioè:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Sembra che Rust sia ancora piuttosto volatile in questo momento con persino IO standard, quindi questo potrebbe diventare obsoleto abbastanza rapidamente.
La ruggine è cambiata di nuovo. os::args()
è deprecato a favore di std::args()
. Ma std::args()
non è un array, restituisce un iteratore . È possibile scorrere gli argomenti della riga di comando, ma non è possibile accedervi con i pedici.
http://doc.rust-lang.org/std/env/fn.args.html
Se vuoi gli argomenti della riga di comando come vettore di stringhe, ora funzionerà:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Ruggine: impara ad abbracciare il dolore del cambiamento.
env::args().collect()
.
cosa dice @barjak per le stringhe, ma se hai bisogno dell'argomento come numero (in questo caso un uint) devi convertirlo in questo modo:
fn main() {
let arg : ~[~str] = os::args();
match uint::from_str(arg[1]){
Some(x)=>io::println(fmt!("%u",someFunction(x))),
None=>io::println("I need a real number")
}
}
Guarda anche structopt:
extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
/// A flag, true if used in the command line.
#[structopt(short = "d", long = "debug", help = "Activate debug mode")]
debug: bool,
/// An argument of type float, with a default value.
#[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
speed: f64,
/// Needed parameter, the first on the command line.
#[structopt(help = "Input file")]
input: String,
/// An optional parameter, will be `None` if not present on the
/// command line.
#[structopt(help = "Output file, stdout if not present")]
output: Option<String>,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
A partire dalle versioni Rust più recenti (Rust> 0,10 / 11) la sintassi dell'array non funzionerà. Dovrai utilizzare il metodo get.
[Modifica] La sintassi dell'array funziona (di nuovo) di notte. Quindi puoi scegliere tra l'indice getter o array.
use std::os;
fn main() {
let args = os::args();
println!("{}", args.get(1));
}
// Compile
rustc args.rs && ./args hello-world // returns hello-world
Vec
s. Immagino sia lì da circa un mese. Vedere questo esempio .
Rust si è evoluto dalla risposta di Calvin del maggio 2013. Ora si analizzano gli argomenti della riga di comando con as_slice()
:
use std::os;
fn seen_arg(x: uint)
{
println!("you passed me {}", x);
}
fn main() {
let args = os::args();
let args = args.as_slice();
let nitems = {
if args.len() == 2 {
from_str::<uint>(args[1].as_slice()).unwrap()
} else {
10000
}
};
seen_arg(nitems);
}
as_slice()
non esiste più e &args
dovrebbe essere usato invece.
Il capitolo "No stdlib" del libro Rust descrive come accedere ai parametri della riga di comando (in un altro modo).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Ora, l'esempio ha anche quello #![no_std]
che penso significhi che normalmente, la libreria std avrebbe il vero punto di ingresso per il tuo binario e chiamerebbe una funzione globale chiamata main()
. Un'altra opzione è "disabilitare lo main
spessore" con #![no_main]
. Il che, se non sbaglio, sta dicendo al compilatore che stai prendendo il pieno controllo su come viene avviato il tuo programma.
#![no_std]
#![no_main]
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: isize, argv: *const *const u8) -> isize {
0
}
Non penso che questo sia un modo "buono" di fare le cose se tutto ciò che vuoi fare è leggere gli argomenti della riga di comando. Il std::os
modulo menzionato in altre risposte sembra essere un modo molto migliore di fare le cose. Pubblico questa risposta per completezza.
println(args[0])