Das Rust-Tutorial erklärt nicht, wie Parameter von der Befehlszeile übernommen werden. fn main()
wird in allen Beispielen nur mit einer leeren Parameterliste angezeigt.
Wie kann über Befehlszeilenparameter korrekt zugegriffen werden main
?
Das Rust-Tutorial erklärt nicht, wie Parameter von der Befehlszeile übernommen werden. fn main()
wird in allen Beispielen nur mit einer leeren Parameterliste angezeigt.
Wie kann über Befehlszeilenparameter korrekt zugegriffen werden main
?
Antworten:
Sie können auf die Befehlszeilenargumente zugreifen, indem Sie die Funktionen std::env::args
oder std::env::args_os
verwenden. Beide Funktionen geben einen Iterator über die Argumente zurück. Ersteres iteriert über String
s (die leicht zu bearbeiten sind), gerät jedoch in Panik, wenn eines der Argumente kein gültiger Unicode ist. Letzteres iteriert über OsString
s und gerät nie in Panik.
Beachten Sie, dass das erste Element des Iterators der Name des Programms selbst ist (dies ist eine Konvention in allen wichtigen Betriebssystemen), sodass das erste Argument tatsächlich das zweite iterierte Element ist.
Eine einfache Möglichkeit, mit dem Ergebnis von umzugehen, args
besteht darin, es in Folgendes umzuwandeln Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
Sie können die gesamte Standard-Iterator-Toolbox verwenden , um mit diesen Argumenten zu arbeiten. Um beispielsweise nur das erste Argument abzurufen:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Auf crates.io finden Sie Bibliotheken zum Parsen von Befehlszeilenargumenten:
Docopt ist auch für Rust verfügbar, das aus einer Verwendungszeichenfolge einen Parser für Sie generiert. Als Bonus in Rust kann ein Makro verwendet werden, um die Struktur automatisch zu generieren und eine typbasierte Dekodierung durchzuführen:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
Und Sie können die Argumente bekommen mit:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
Die README-Datei und die Dokumentation enthalten zahlreiche vollständige Arbeitsbeispiele.
Haftungsausschluss: Ich bin einer der Autoren dieser Bibliothek.
Rust hat ein getopt
CLI-Argument im Stil, das in der getopts-Kiste analysiert wird .
Getopts fühlte sich für mich immer zu niedrig an und docopt.rs war zu viel Magie. Ich möchte etwas Explizites und Unkompliziertes, das immer noch alle Funktionen bietet, wenn ich sie brauche.
Hier bietet sich das Klatschen an.
Es fühlt sich ein bisschen wie Argparse aus Python an. Hier ist ein Beispiel, wie es aussieht:
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();
Sie können wie folgt auf Ihre Parameter zugreifen:
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);
(Aus der offiziellen Dokumentation kopiert )
Ab Version 0.8 / 0.9 wäre der korrekte Pfad zur Funktion args () ::std::os::args
:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Es scheint, dass Rust derzeit selbst mit Standard-E / A noch ziemlich volatil ist, so dass dies ziemlich schnell veraltet sein kann.
Rust änderte sich wieder. os::args()
wird zugunsten von abgelehnt std::args()
. Ist std::args()
aber kein Array, gibt es einen Iterator zurück . Sie können über die Befehlszeilenargumente iterieren, jedoch nicht mit Indizes darauf zugreifen.
http://doc.rust-lang.org/std/env/fn.args.html
Wenn Sie die Befehlszeilenargumente als Vektor von Zeichenfolgen verwenden möchten, funktioniert dies jetzt:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Rost - lernen Sie, den Schmerz der Veränderung anzunehmen.
env::args().collect()
.
Was @barjak gesagt hat, funktioniert für Zeichenfolgen, aber wenn Sie das Argument als Zahl (in diesem Fall als Uint) benötigen, müssen Sie Folgendes konvertieren:
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")
}
}
Schauen Sie sich auch structopt an:
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);
}
Ab neueren Rust-Versionen (Rust> 0.10 / 11) funktioniert die Array-Syntax nicht mehr. Sie müssen die get-Methode verwenden.
[Bearbeiten] Die Array-Syntax funktioniert (wieder) in der Nacht. Sie können also zwischen dem Getter- oder dem Array-Index wählen.
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. Ich denke, es ist ungefähr einen Monat lang da. Siehe dieses Beispiel .
Rust hat sich seit Calvins Antwort vom Mai 2013 weiterentwickelt. Nun würde man Befehlszeilenargumente analysieren mit 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()
existiert nicht mehr und &args
sollte stattdessen verwendet werden.
Das Kapitel "No stdlib" im Rust-Buch behandelt den Zugriff auf die Befehlszeilenparameter (auf andere Weise).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Das Beispiel hat auch das, #![no_std]
was meiner Meinung nach bedeutet, dass die Standardbibliothek normalerweise den wahren Einstiegspunkt für Ihre Binärdatei hat und eine globale Funktion namens aufruft main()
. Eine andere Möglichkeit besteht darin, die main
Unterlegscheibe mit zu deaktivieren #![no_main]
. Wenn ich mich nicht irre, sagt das dem Compiler, dass Sie die volle Kontrolle darüber haben, wie Ihr Programm gestartet wird.
#![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
}
Ich denke nicht, dass dies eine 'gute' Art ist, Dinge zu tun, wenn Sie nur Befehlszeilenargumente lesen möchten. Das std::os
in anderen Antworten erwähnte Modul scheint eine viel bessere Möglichkeit zu sein, Dinge zu tun. Ich poste diese Antwort zum Zwecke der Vervollständigung.
println(args[0])