Le didacticiel Rust n'explique pas comment utiliser les paramètres de la ligne de commande. fn main()
apparaît uniquement avec une liste de paramètres vide dans tous les exemples.
Quelle est la manière correcte d’accéder aux paramètres de ligne de commande à partir de main
?
Vous pouvez accéder aux arguments de la ligne de commande en utilisant le std::env::args
ou std::env::args_os
fonctions. Les deux fonctions renvoient un itérateur sur les arguments. La première itère sur String
s (avec laquelle il est facile de travailler) mais panique si l’un des arguments n’est pas unicode valide. Ce dernier itère sur OsString
s et ne panique jamais.
Notez que le premier élément de l'itérateur est le nom du programme lui-même (il s'agit d'une convention dans tous les principaux systèmes d'exploitation), de sorte que le premier argument est en réalité le deuxième élément itéré.
Un moyen simple de gérer le résultat de args
consiste à le convertir en un fichier Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
Vous pouvez utiliser la totalité boîte à outils itérateur standard pour travailler avec ces arguments. Par exemple, pour récupérer uniquement le premier argument:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Vous pouvez trouver des bibliothèques sur crates.io pour analyser les arguments en ligne de commande:
Docopt est également disponible pour Rust, qui génère un analyseur syntaxique pour vous à partir d'une chaîne d'utilisation. En bonus dans Rust, une macro peut être utilisée pour générer automatiquement la structure et effectuer un décodage basé sur le type:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
Et vous pouvez obtenir les arguments avec:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
Les README et documentation ont de nombreux exemples de travail complets.
Disclaimer: Je suis l'un des auteurs de cette bibliothèque.
Rust a l'argument de l'argument CLI de style getopt
- dans caisse getopts .
Pour moi, getopts se sentait toujours trop bas et docopt.rs était trop magique. Je veux quelque chose de simple et explicite qui fournit toutes les fonctionnalités si j'en ai besoin.
C’est là que clap-rs est pratique.
Cela ressemble un peu à argparse de Python. Voici un exemple de ce à quoi il ressemble:
let matches = App::new("myapp")
.version("1.0")
.author("Kevin K. <[email protected]>")
.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();
Vous pouvez accéder à vos paramètres comme suit:
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);
(Copié à partir du documentation officielle )
A partir de la version 0.8/0.9, le chemin correct pour la fonction args () serait ::std::os::args
, c'est à dire:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Il semble que Rust soit encore assez volatile, même avec les entrées/sorties standard, ce qui risque de devenir obsolète assez rapidement.
La rouille a encore changé. os::args()
est déconseillé en faveur de std::args()
. Mais std::args()
n'est pas un tableau, il retourne un itérateur . Vous pouvez parcourir les arguments de la ligne de commande, mais vous ne pouvez pas y accéder avec des indices.
http://doc.Rust-lang.org/std/env/fn.args.html
Si vous voulez que les arguments de la ligne de commande soient utilisés comme vecteur de chaînes, cela fonctionnera maintenant:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Rust - apprenez à accepter la douleur du changement.
ce que @barjak dit fonctionne pour les chaînes, mais si vous avez besoin de l'argument sous forme de nombre (dans ce cas, un uint), vous devez convertir comme ceci:
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")
}
}
Consultez également 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);
}
Le chapitre Le livre Rust, "No stdlib" explique comment accéder aux paramètres de la ligne de commande (autre moyen).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Maintenant, l’exemple contient également #![no_std]
, Ce qui, je pense, signifie que, normalement, la bibliothèque std aurait le véritable point d’entrée pour votre binaire et appellerait une fonction globale appelée main()
. Une autre option consiste à "désactiver le main
shim" avec #![no_main]
. Ce qui, si je ne me trompe pas, dit au compilateur que vous prenez le contrôle total du démarrage de votre programme.
#![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
}
Je ne pense pas que ce soit une "bonne" façon de faire les choses si tout ce que vous voulez faire est de lire les arguments en ligne de commande. Le module std::os
Mentionné dans d'autres réponses semble être une bien meilleure façon de faire les choses. Je publie cette réponse par souci d'achèvement.
À partir de plus récent Rust versions (Rust> 0.10/11), la syntaxe du tableau ne fonctionnera pas. Vous devrez utiliser la méthode get.
[Edit] La syntaxe du tableau fonctionne (encore) la nuit. Vous pouvez donc choisir entre le getter ou l’index de tableau.
use std::os;
fn main() {
let args = os::args();
println!("{}", args.get(1));
}
// Compile
rustc args.rs && ./args hello-world // returns hello-world
La rouille a évolué depuis la réponse de Calvin à compter de mai 2013. On analysera maintenant les arguments en ligne de commande avec 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);
}