简体   繁体   中英

Using a structure as a command line argument in clap

Trying to use a struct within a struct in clap :

use clap::{Args, Parser};
use std::path::PathBuf;

#[derive(Parser, Debug)]
enum Command {
    Foo(Foo),
}

#[derive(Args, Debug)]
struct Foo {
    bar: Option<Bar>,

    path: PathBuf,
}

#[derive(Parser, Clone, Debug)]
struct Bar {
    bla: u8,

    bla_2: String,
}

fn main() {
    let cli = Command::parse();
    println!("cli {:#?}", cli);
}

So I could call the app with the following options: cargo run -- foo bar 42 baz /tmp/a or just cargo run -- foo /tmp/a since the bar argument is optional.

However, currently it does not build:

  --> src/main.rs:11:5
   |
11 |     bar: Option<Bar>,
   |     ^^^ the trait `FromStr` is not implemented for `Bar`
   |

And since the values within Bar have to be space-separated implementing a FromStr would not do the trick anyway.

Is it even possible to do something of this fashion in clap currently?

There are several problems with your code. The biggest one is:

  • An optional positional item can never come before a required positional argument

This is a problem in your case because your command line looks like this:

cargo run -- <required> [optional] /tmp/a

If you have a required path at the end, there can not be an optional positional argument before that.

Further problems:

  • #[derive(Parser)] should be attached to a struct , not an enum .
  • There should only be one #[derive(Parser)] , which represents the entry object of your arguments parser.

I'm unsure how else to help you, except pointing out your problems. If the invocations cargo run -- foo bar 42 baz /tmp/a and cargo run -- foo /tmp/a are non-negotiable, I don't think clap is the right library for you; I think you should parse by hand.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM