O tutorial Rust não explica como obter parâmetros da linha de comando. fn main()
é mostrado apenas com uma lista de parâmetros vazia em todos os exemplos.
Qual é a maneira correta de acessar os parâmetros da linha de comando main
?
O tutorial Rust não explica como obter parâmetros da linha de comando. fn main()
é mostrado apenas com uma lista de parâmetros vazia em todos os exemplos.
Qual é a maneira correta de acessar os parâmetros da linha de comando main
?
Respostas:
Você pode acessar os argumentos da linha de comando usando as funções std::env::args
ou std::env::args_os
. Ambas as funções retornam um iterador sobre os argumentos. O primeiro itera sobre String
s (que são fáceis de trabalhar), mas entra em pânico se um dos argumentos não for um unicode válido. O último repete sobre se OsString
nunca entra em pânico.
Observe que o primeiro elemento do iterador é o nome do próprio programa (essa é uma convenção em todos os principais sistemas operacionais); portanto, o primeiro argumento é realmente o segundo elemento iterado.
Uma maneira fácil de lidar com o resultado de args
é convertê-lo para Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
Você pode usar toda a caixa de ferramentas do iterador padrão para trabalhar com esses argumentos. Por exemplo, para recuperar apenas o primeiro argumento:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Você pode encontrar bibliotecas em crates.io para analisar argumentos da linha de comandos:
O Docopt também está disponível para o Rust, que gera um analisador para você a partir de uma sequência de uso. Como um bônus no Rust, uma macro pode ser usada para gerar automaticamente a estrutura e decodificar com base no tipo:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
E você pode obter os argumentos com:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
O README e a documentação têm muitos exemplos de trabalho completos.
Disclaimer: Eu sou um dos autores desta biblioteca.
Rust possui um getopt
argumento de CLI no estilo, analisando na caixa de getopts .
Para mim, os getopts sempre pareciam muito baixos e o docopt.rs era muito mágico. Quero algo explícito e direto que ainda ofereça todos os recursos, se eu precisar.
É aqui que o clap-rs é útil.
Parece um pouco com o argparse do Python. Aqui está um exemplo de como ele se parece:
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();
Você pode acessar seus parâmetros assim:
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);
(Copiado da documentação oficial )
A partir da versão 0.8 / 0.9, o caminho correto para a função args () seria ::std::os::args
, ou seja:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Parece que o Rust ainda é bastante volátil no momento, mesmo com IO padrão, portanto, isso pode ficar desatualizado rapidamente.
Ferrugem mudou novamente. os::args()
foi descontinuado em favor de std::args()
. Mas std::args()
não é uma matriz, ele retorna um iterador . Você pode iterar sobre os argumentos da linha de comando, mas não pode acessá-los com subscritos.
http://doc.rust-lang.org/std/env/fn.args.html
Se você quiser os argumentos da linha de comando como um vetor de strings, isso funcionará agora:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Ferrugem - aprenda a abraçar a dor da mudança.
env::args().collect()
.
o que o @barjak disse funciona para strings, mas se você precisar do argumento como um número (neste caso, um uint), precisará converter assim:
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")
}
}
Confira também o 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 partir das versões mais recentes do Rust (Rust> 0,10 / 11), a sintaxe da matriz não funciona. Você precisará usar o método get.
[Editar] A sintaxe da matriz funciona (novamente) à noite. Assim, você pode escolher entre o índice getter ou 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. Eu acho que está lá por mais ou menos um mês. Veja este exemplo .
O Rust evoluiu desde a resposta de Calvin em maio de 2013. Agora, seria possível analisar os argumentos da linha de comando com 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()
não existe mais e &args
deve ser usado.
O capítulo "No stdlib" do livro Rust aborda como acessar os parâmetros das linhas de comando (outra maneira).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Agora, o exemplo também possui o #![no_std]
que eu acho que significa que, normalmente, a biblioteca std teria o verdadeiro ponto de entrada para o seu binário e chamaria uma função global chamada main()
. Outra opção é 'desativar o main
calço' com #![no_main]
. O que, se não me engano, é dizer ao compilador que você está assumindo o controle total sobre como o programa é iniciado.
#![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
}
Eu não acho que essa seja uma maneira 'boa' de fazer as coisas se tudo o que você quer fazer é ler os argumentos da linha de comando. O std::os
módulo mencionado em outras respostas parece ser uma maneira muito melhor de fazer as coisas. Eu posto esta resposta para fins de conclusão.
println(args[0])