rust Clap -子命令可能具有共享的默认值集?

yyyllmsg  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(205)

我在这个问题上兜圈子已经有一段时间了,还没有找到一个好的解决办法:
我在同一个代码库中有一堆模拟。我试着像个成年人一样,使用命令行参数来选择运行哪些模拟以及使用哪些参数。问题是,许多参数在不同的模拟之间共享,有些参数集传递给共享组件。
例如,下面我有三个模拟,其中两个共享"Threaded"参数子集,另外两个共享MazeCli参数子集,这是Maze trait所需要的(在完整的模拟中,有更多的参数和组合)。

use clap::*;

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

#[derive(Subcommand, Debug)]
enum Simulation {
    Maze {
        maze_args: MazeCli,
        thread_args: ThreadCli,
    },
    ThreadedMaze {
        maze_args: MazeCli,
    },
    Threaded {
        thread_args: ThreadCli,
    },
}

trait Maze {
    fn new(args: MazeCli) -> Self;
}

#[derive(Args, Debug, Clone)]
struct MazeCli {
    squares: usize,
    openness: f64,
}

#[derive(Args, Debug, Clone)]
struct ThreadCli {
    threads: usize,
}
fn main() {
    let config = Cli::parse();
    println!("{:?}", config);
}

这个版本失败了,因为它想让MazeCliThreadCli实现ValueEnum(据我所知-实际的错误很长,没有帮助)。ValueEnum不能为结构体派生。我尝试了一些其他的方法,但没有得到任何编译。
我可以用一个简单的arg列表来完成所有的事情,但是错误消息不会告诉您运行的特定子命令需要什么。
我可以手动指定每个列表,但这是一堆样板文件,特别是在考虑默认值的情况下。
正确的方法是什么?它是拍手支持的东西吗?
附加问题:

  • 如果这是可能的,那么特定的子命令是否有办法覆盖其特定情况下的通用默认值(例如,如果一个模拟在默认情况下需要两倍于标准的线程)。
  • 我可以让default值以某种方式回退到该结构体的Default trait实现吗?
9gm1akwq

9gm1akwq1#

使用#[command(flatten)]

#[derive(Subcommand, Debug)]
enum Simulation {
    Maze {
        #[command(flatten)]
        maze_args: MazeCli,
        #[command(flatten)]
        thread_args: ThreadCli,
    },
    ThreadedMaze {
        #[command(flatten)]
        maze_args: MazeCli,
    },
    Threaded {
        #[command(flatten)]
        thread_args: ThreadCli,
    },
}

我可以让默认值以某种方式回退到该结构体的Default trait实现吗?
使用default_value_t,不带参数,默认为Default::default()

#[derive(Args, Debug, Clone)]
struct MazeCli {
    #[arg(long, default_value_t)]
    squares: usize, // Will be optional with a default of 0
    openness: f64,
}

如果这是可能的,那么特定的子命令是否有办法覆盖其特定情况下的通用默认值(例如,如果一个模拟在默认情况下需要两倍于标准的线程)。
我认为不使用单独的结构体是不可能的。

相关问题