我有一个命令行工具,它有两个可能的参数:

  • --version(将打印出版本号并退出)
  • --out(这是指向某个输出文件的路径,魔法将被注入其中).

如果用户通过--version,我不关心--out,因为我打印版本,我完成了but,如果他们不通过--version,我希望--out是必需的.

这就是我所拥有的,但我想知道是否有任何方法可以只用structopt来实现这一点?

It seems like I may end up needing to make all my arguments optional and do all the validation myself...

#![feature(custom_attribute)]
#[macro_use]
extern crate structopt;

use structopt::StructOpt;
use std::path::PathBuf;

#[derive(Debug, StructOpt)]
#[structopt(name = "structopt_playing", about = "Just playing")]
struct Opt {
    #[structopt(short = "v", long = "version")]
    version: bool,

    #[structopt(short = "o", long = "out", parse(from_os_str))]
    output_file: Option<PathBuf>,
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn main() {

    let opt = Opt::from_args();
    if opt.version {
        println!("Version: {}", VERSION);
        return;
    }

    if !opt.output_file.is_some() {
        println!("Oh, now I feel like I'm alone...you need to pass --out");
        return;
    }

    println!("Now I'm going to need to do something with {:?}", 
        opt.output_file.unwrap());
}

推荐答案

使用required_unless:

#[derive(Debug, StructOpt)]
#[structopt(name = "structopt_playing", about = "Just playing")]
struct Opt {
    #[structopt(short = "v", long = "version")]
    version: bool,

    #[structopt(short = "o", long = "out", parse(from_os_str), required_unless = "version")]
    //                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    output_file: Option<PathBuf>,
}
$ ./target/debug/stropt
error: The following required arguments were not provided:
    --out <output_file>

USAGE:
    stropt --out <output_file>

For more information try --help

$ ./target/debug/stropt --out hello
Now I'm going to need to do something with "hello"

$ ./target/debug/stropt --version
Version: 0.1.0

Clap提供了大量相关的配置选项:

  • required_unless
  • required_unless_all
  • required_unless_one
  • conflicts_with
  • conflicts_with_all
  • requires
  • requires_if
  • requires_ifs
  • required_if
  • required_ifs
  • requires_all

附带说明:在这段代码中根本不需要使用#![feature(custom_attribute)].

Rust相关问答推荐

为什么实例化核心::time::ns不安全?

WebDriver等待三十四?(Rust Se)

为什么要在WASM库中查看Rust函数需要`#[no_mangle]`?

如何实现泛型枚举的`Serde::Desialize`特性

像这样的铁 rust 图案除了‘选项’之外,还有其他 Select 吗?

将serde_json读入`VEC<;T&>;`( rust 色)时出现问题

如何使用Actix Web for Rust高效地为大文件服务

从字节数组转换为字节元组和字节数组时,为什么 Transmute 会对字节重新排序?

需要哪些编译器优化来优化此递归调用?

如何基于常量在Rust中跳过一个测试

Rust typestate 模式:实现多个状态?

Rust 编译器不统一在 if let 表达式的分支中都 impl Future 的类型

有没有办法隐式绑定 let/match 操作的成员?

push 方法是否取得所有权?

为什么不可变特征的实现可以是可变的?

打印 `format_args!` 时borrow 时临时值丢失

Rust 引用元组和引用元组

使用 HashMap 条目时如何避免字符串键的短暂克隆?

在单独的线程上运行 actix web 服务器

当 `T` 没有实现 `Debug` 时替代 `unwrap()`