Разбор флагов командной строки с аргументами с использованием docopt и Rust, аналогично getopt

Я ищу способ подражать тому, как C использует getopt. Я хочу преобразовать следующий фрагмент C в Rust с помощью docopt. Кажется, я не могу передавать флаги в аргумент командной строки:

char in;
char* stringName;
while(( in = getopt( argc, argv, "a:b:c:d:e:")) != EOF) {
    switch(in) {
        case 'a':
            stringName = optarg;
            break;
     // ... and so on

Тогда я хочу бежать

cargo run -a "hello" -b 3 ... and so on

Я написал это до сих пор:

extern crate rustc_serialize;
extern crate docopt;

use docopt::Docopt;

// Define a USAGE string
const USAGE: &'static str = "
Program.

Usage: [options] [<value1>] [options] [<value2>] [options] [<value3>] [options] [<value4>]

Options:
    -a, 
    -b, 
    -c,
    -d,  
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_value1: Option<String>,
    flag_a: bool,
    flag_b: bool,
    flag_c: bool,
    arg_value2: Option<String>,
    arg_value3: Option<String>,
    arg_value4: Option<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);
}

Когда я cargo run, я получаю

неизвестный флаг -a


person Bump the Trump    schedule 13.04.2016    source источник
comment
Пожалуйста, покажите код, который вы пробовали, и какие проблемы у вас были с ним   -  person oli_obk    schedule 13.04.2016
comment
@ker Я добавил его в правку   -  person Bump the Trump    schedule 13.04.2016
comment
Я не думаю, что ваша спецификация docopt делает то, что вы думаете. Как узнать, какой флаг установлен для какого значения? Полученная структура Args будет иметь одинаковые значения для program -a "hi" -b 2 и program -b "hi" -a 2   -  person oli_obk    schedule 13.04.2016
comment
@ker окей, я вижу, что с этим не так.   -  person Bump the Trump    schedule 13.04.2016
comment
Однако есть еще одна проблема. Вы упомянули, что используете cargo run, верно? Чтобы он правильно передавал аргументы программе, вам необходимо указать их после двойного дефиса, например: cargo run -- -a "hi" -b 2. В противном случае cargo run не сможет решить, какие параметры направлены на себя, а какие - на программу. Но, тем не менее, опасения @ker абсолютно справедливы. Честно говоря, я не уверен, могут ли библиотеки синтаксического анализа аргументов делать то, что вы хотите (до четырех аргументов, с разными флагами для каждого). Скорее всего, вам придется реализовать синтаксический анализ самостоятельно.   -  person Vladimir Matveev    schedule 13.04.2016


Ответы (1)


Что-то вроде этого, вероятно, подберет вас довольно близко:

const USAGE: &'static str = "
Program.

Usage: program [options]

Options:
    -a VALUE
    -b VALUE
    -c VALUE
    -d VALUE
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_a: Option<String>,
    flag_b: Option<i32>,
    flag_c: Option<String>,
    flag_d: Option<String>,
}

При запуске с cargo run -- -a "hello" -b 3 (см. Примечание ниже) вывод будет следующим:

Args { flag_a: Some("hello"), flag_b: Some(3), flag_c: None, flag_d: None }

Затем вы можете сопоставить шаблон flag_a, чтобы узнать, был ли он предоставлен (и, таким образом, получить значение). Нет необходимости иметь отдельные логические флаги, в этом случае лучше использовать Option.


Как Владимир Матвеев указывает, что когда вы выполняете свою программу через cargo run, вы должны отличать аргументы для cargo от аргументов для вашей программы. Большинство (все?) Программ, которые делают это, используют специальный флаг --. Это разделяет аргументы между программами. Вы также можете запустить программу сразу после ее создания:

$ cargo build
$ ./target/debug/program_name -a "hello" -b 3 
person Shepmaster    schedule 13.04.2016
comment
Это очень информативно. Итак, всякий раз, когда вы анализируете аргументы командной строки, которые используют флаг, вы всегда должны использовать - в качестве первого аргумента командной строки? - person Bump the Trump; 13.04.2016
comment
@BumptheTrump нет, это не совсем правильно. Я добавил примечание. - person Shepmaster; 13.04.2016