Rust tutorial не объясняет, как взять параметры из командной строки. fn main()
отображается только с пустым списком параметров во всех примерах.
Каков правильный способ доступа к параметрам командной строки из main
?
Rust tutorial не объясняет, как взять параметры из командной строки. fn main()
отображается только с пустым списком параметров во всех примерах.
Каков правильный способ доступа к параметрам командной строки из main
?
Вы можете получить доступ к аргументам командной строки, используя функции std::env::args
или std::env::args_os
. Обе функции возвращают итератор для аргументов. Первый перебирает String
(с которым легко работать), но паникует, если один из аргументов недопустим в Юникоде. Последний перебирает OsString
и никогда не паникует.
Обратите внимание, что первым элементом итератора является имя самой программы (это соглашение во всех основных ОС), поэтому первый аргумент на самом деле является вторым итеративным элементом.
Простой способ справиться с результатом args
- преобразовать его в Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
Вы можете использовать весь стандартный набор инструментов итератора для работы с этими аргументами. Например, чтобы получить только первый аргумент:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Вы можете найти библиотеки на crates.io для анализа аргументов командной строки:
Docopt также доступен для Rust, который генерирует для вас парсер из строки использования. В качестве бонуса в Rust можно использовать макрос для автоматической генерации структуры и декодирования на основе типов:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
И вы можете получить аргументы с:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
README и документация содержат множество полных рабочих примеров.
Отказ от ответственности: я один из авторов этой библиотеки.
У Rust есть синтаксический анализ аргумента getopt
-style в ящике getopts.
Для меня, getopts всегда чувствовали себя слишком низкоуровневыми, и docopt.rs было слишком много волшебства. Я хочу что-то явное и прямолинейное, которое все еще предоставляет все функции, если они мне нужны.
Здесь clap-rs пригодится.
Он чувствует себя немного похоже на argparse от Python.
Вот пример того, как это выглядит:
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();
Вы можете получить доступ к своим параметрам следующим образом:
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);
(Скопировано из официальной документации )
Начиная с версии 0.8/0.9, правильный путь к функции args() будет ::std::os::args
, то есть:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Кажется, что Rust по-прежнему довольно изменчив, даже с стандартным IO, поэтому это может устареть довольно быстро.
Ржавчина снова изменилась. os::args()
устарел в пользу std::args()
. Но std::args()
не является массивом, он возвращает итератор. Вы можете перебирать аргументы командной строки, но не можете обращаться к ним с помощью индексов.
http://doc.rust-lang.org/std/env/fn.args.html
Если вам нужны аргументы командной строки в виде вектора строк, это будет работать теперь:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Ржавчина - научитесь обнимать боль изменений.
то, что @barjak говорит, работает для строк, но если вам нужен аргумент как число (в этом случае uint), вам нужно преобразовать вот так:
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")
}
}
Как и в случае с новыми версиями Rust (Rust > 0.10/11), синтаксис массива не будет работать. Вы будете использовать метод get.
[Edit] Синтаксис массива работает (снова) в ночное время. Таким образом, вы можете выбирать между индексом getter или array.
use std::os;
fn main() {
let args = os::args();
println!("{}", args.get(1));
}
// Compile
rustc args.rs && ./args hello-world // returns hello-world
Rust развился с момента ответа Кальвина с мая 2013 года. Теперь можно проанализировать аргументы командной строки с помощью 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);
}
Ручная книга "Нет stdlib" главу описывает, как получить доступ к параметрам командной строки (по-другому).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Теперь в примере также есть #![no_std]
, который, как мне кажется, означает, что обычно библиотека std будет иметь истинную точку входа для вашего двоичного кода и вызовет глобальную функцию с именем main()
. Другими параметрами являются "отключить main
прокладку" с помощью #![no_main]
. Что, если я не ошибаюсь, говорит компилятору, что вы полностью контролируете, как запускается ваша программа.
#![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
}
Я не думаю, что это "хороший" способ делать вещи, если все, что вы хотите сделать, это прочитать аргументы командной строки. Модуль std::os
, упомянутый в других ответах, кажется, намного лучший способ делать вещи. Я отправляю этот ответ ради завершения.
Также проверьте 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);
}