我试图在rust中创建一些简单的计费CLI应用程序,以供实践。它是一种数据库应用程序。我有许多操作,我需要用户能够通过列的值过滤哪些行将被操作。
下面的示例包含delete和show命令:
#[derive(Debug, Args)]
struct DeleteCommand {
/// The ID of the bill
#[clap(short, long, value_parser)]
id: Option<String>,
/// The name of the bill
#[clap(short, long, value_parser)]
name: Option<String>,
/// The value of the bill
#[clap(short, long, value_parser)]
value: Option<String>,
/// The amount of the billB
#[clap(short, long, value_parser)]
amount: Option<String>,
/// Datetime
#[clap(short, long, value_parser)]
datetime: Option<String>,
/// Currency
#[clap(short, long, value_parser)]
currency: Option<String>,
/// Recipient
#[clap(short, long, value_parser)]
recipient: Option<String>,
/// Situation
#[clap(short, long, value_parser)]
situation: Option<String>,
/// Hard
#[clap(short = 'H', long)]
hard: bool,
}
#[derive(Debug, Args)]
struct ShowCommand {
#[clap(subcommand)]
subcommand: ShowSubcommand,
/// The ID of the bill
#[clap(short, long, value_parser)]
id: Option<String>,
/// The name of the bill
#[clap(short, long, value_parser)]
name: Option<String>,
/// The value of the bill
#[clap(short, long, value_parser)]
value: Option<String>,
/// The amount of the bill
#[clap(short, long, value_parser)]
amount: Option<String>,
/// Datetime
#[clap(short, long, value_parser)]
datetime: Option<String>,
/// Currency
#[clap(short, long, value_parser)]
currency: Option<String>,
/// Datetime
#[clap(short, long, value_parser)]
recipient: Option<String>,
/// Datetime
#[clap(short, long, value_parser)]
situation: Option<String>,
/// Head
#[clap(long, value_parser)]
head: Option<u32>,
/// Tail
#[clap(long, value_parser)]
tail: Option<u32>,
/// Order by
#[clap(short, long, value_parser)]
orderby: Option<String>,
}
正如你所看到的,两个结构体之间有许多公共字段,因为都需要for来过滤数据库中的项。我只想创建一个派生自定义宏,它允许我在结构体中简单地重复这些行,而不需要一遍又一遍地编写它:
/// The ID of the bill
#[clap(short, long, value_parser)]
id: Option<String>,
/// The name of the bill
#[clap(short, long, value_parser)]
name: Option<String>,
/// The value of the bill
#[clap(short, long, value_parser)]
value: Option<String>,
/// The amount of the bill
#[clap(short, long, value_parser)]
amount: Option<String>,
/// Datetime
#[clap(short, long, value_parser)]
datetime: Option<String>,
/// Currency
#[clap(short, long, value_parser)]
currency: Option<String>,
/// Recipient
#[clap(short, long, value_parser)]
recipient: Option<String>,
/// Situation
#[clap(short, long, value_parser)]
situation: Option<String>,
我还需要重复///行,因为它将成为CLI中每个参数的描述。
最小重现示例:
这是我的
use clap::{Parser, Subcommand, Args};
#[derive(Debug, Parser)]
pub struct UserInput {
#[clap(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
/// A command description
A(CommandA),
/// B command description
B(CommandB),
}
#[derive(Debug, Args)]
struct CommandA {
/// The value of column x to be filtered in the database
#[clap(short, long, value_parser)]
x_value: Option<String>,
/// The value of column y to be filtered in the database
#[clap(short, long, value_parser)]
y_value: Option<String>,
/// Some particular parameter of this command
#[clap(short, long, value_parser)]
particular: Option<String>,
}
#[derive(Debug, Args)]
struct CommandB {
/// The value of x to be filtered in the database
#[clap(short, long, value_parser)]
x_value: Option<String>,
/// The value of y to be filtered in the database
#[clap(short, long, value_parser)]
y_value: Option<String>,
/// Some particular parameter of this command
#[clap(short, long, value_parser)]
particular: Option<String>,
}
fn main() {
let user_input: UserInput = UserInput::parse();
print!("{:#?}", user_input)
}
这就是我想要的
use clap::{Parser, Subcommand, Args};
#[derive(Debug, Parser)]
pub struct UserInput {
#[clap(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
/// A command description
A(CommandA),
/// B command description
B(CommandB),
}
#[derive(Debug, Args, Filter)]
struct CommandA {
/// Some particular parameter command A
#[clap(short, long, value_parser)]
particular: Option<String>,
}
#[derive(Debug, Args, Filter)]
struct CommandB {
/// Some particular parameter command B
#[clap(short, long, value_parser)]
particular: Option<String>,
}
fn main() {
let user_input: UserInput = UserInput::parse();
print!("{:#?}", user_input)
}
等待行为:
[user@host appname]$ appname a --help
p1-a
A command description
USAGE:
p1 a [OPTIONS]
OPTIONS:
-x, --x-value <X_VALUE> The value of column X to be filtered in the database
-y, --y-value <Y_VALUE> The value of column Y to be filtered in the database
-h, --help Print help information
-p, --particular <PARTICULAR> Some particular parameter of command A
编辑:我使用的是clap 3.2.22,但我会尽量把代码移到最新版本。
1条答案
按热度按时间mf98qq941#
通过使用composition沿着
#[clap(flatten)]
,您几乎可以实现您想要的效果,如下所示:唯一的区别是,在访问时,您可以多输入一级间接。
这个“缺点”伴随着一个优点,那就是你可以更容易地传递部分参数,例如为
ArgsA
和ArgsB
实现AsRef<CommonArgs>
。