rust 如何用Clap解析常见的子命令参数?

ql3eal8s  于 2023-02-23  发布在  其他
关注(0)|答案(1)|浏览(190)

我尝试构建cli,它应该将<command_name>作为第一个参数,将<path_to_file>作为最后一个参数,并在这两个参数之间使用选项,因此在控制台中的调用如下所示:

programm command_one --option True file.txt

我有这样的设置:

// ./src/main.rs
use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Cli {
   #[command(subcommand)]
   command: Commands,
}

#[derive(Args, Debug)]
struct CommandOneArgs {
   file: String,
   #[arg(short, long)]
   option_for_one: Option<String>,
}

#[derive(Args, Debug)]
struct CommandTwoArgs {
   file: String,
   #[arg(short, long)]
   option_for_two: Option<String>,
}

#[derive(Subcommand, Debug)]
enum Commands {
   CmdOne(CommandOneArgs)
   CmdTwo(CommandTwoArgs)
}

fn main() {
   let args = Cli::parse();
   match &args.command {
      Commands::CmdOne(cmd_args) => {println!({:?}, cmd_args)}
      Commands::CmdTwo(cmd_args) => {println!({:?}, cmd_args)}
      _ => {}
   }

但这里有一个问题,我没有解决:
实际上,在match的分支中,我会用获得的参数调用一些函数;
然而,我需要为所有命令做好准备,例如从路径读取文件
因此,在匹配表达式之前,我需要提取file属性:

fn main() {
   let args = Cli::parse();
   /// something like that
   // let file_path = args.command.file;
   // println!("reading from: {}", file_path)
   match &args.command {
      Commands::CmdOne(cmd_args) => {println!({:?}, cmd_args)}
      Commands::CmdTwo(cmd_args) => {println!({:?}, cmd_args)}
      _ => {}
   }

我不能像评论的那样做。
而且我不能将位置参数添加到Cli结构体,因为接口看起来像:programm <POSITIONAL ARG> command_one ...
我假设我应该使用泛型,但我不知道如何使用。

qvsjd97n

qvsjd97n1#

将获取file参数值的逻辑抽象到CommandsCli上的方法中是否是您的一个选项?

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

impl Cli {
    fn file(&self) -> &str {
        self.command.file()
    }
}

#[derive(Args, Debug)]
struct CommandOneArgs {
    file: String,
    #[arg(short, long)]
    option_for_one: Option<String>,
}

#[derive(Args, Debug)]
struct CommandTwoArgs {
    file: String,
    #[arg(short, long)]
    option_for_two: Option<String>,
}

#[derive(Subcommand, Debug)]
enum Commands {
    CmdOne(CommandOneArgs),
    CmdTwo(CommandTwoArgs),
}

impl Commands {
    fn file(&self) -> &str {
        match self {
            Self::CmdOne(args) => &args.file,
            Self::CmdTwo(args) => &args.file,
        }
    }
}

fn main() {
    let args = Cli::parse();

    let file_path = args.file();

    println!("{file_path}");
}

如果运行cargo run -- cmd-one hello,则打印hello

相关问题