如何在 Rust 中使用 Clap 解析常见的子命令参数?

问题描述 投票:0回答:1

我正在尝试构建 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)}
      _ => {}
   }

但这是我未能解决的问题:
实际上,在匹配的分支中,我会用获得的参数调用一些函数;
但是我需要为所有命令做通用的准备工作,例如从路径读取文件
所以在匹配表达式之前我需要提取

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 ...

我假设我应该使用泛型,但我不知道如何使用。

rust command-line-interface clap
1个回答
0
投票

将检索

file
参数的值的逻辑抽象为
Commands
Cli
上的方法是否适合您?像这样的东西:

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}");
}

打印

hello
如果我运行
cargo run -- cmd-one hello
.

© www.soinside.com 2019 - 2024. All rights reserved.