之前学习了Rust
中的Clap crate
, 前几天又接触了Rust
实现的一个命令行记录工具Atuin
, 他的命令行参数就是使用Clap
实现, 并且参数众多, 做了不同的分层. 今天就扒一扒Atuin
的实现方式, 加深一下对Clap
的理解.
下图是整理的Atuin部分命令配置:
首先观察紫色的这条线部分, 并结合前部在AtuinCmd
和client::Cmd
添加的subcommand
和flatten
可以知道, history
应该是最上层的命令, 这从帮助信息中可以看到. 再观察紫色框中的内容, 可以知道history
会有 start
, end
, list
, last
这些命令, 同时需要输入的参数是, command, id, cwd, session等.
再观察酒红色这一部分, 这里使用的是Parser
派生. 同时命令参数的类型是enum
, 没有附加数据. 这些命令每次只能指定一个, 并且不带有参数.
接下来看绿色方框的部分, 这里使用Commands
类型又多做了一层封装. 如果换成红色方框的结构, 也可以编译通过. 在Commands
中的类型是命令, 而在比如login::Cmd
中的类型就是参数, 使用的是Parser
派生.
总结:
在Atuin
的代码中, 可以看到它是使用#[command(flatten)]
#[command(subcomannd)]
#[derive(Subcommand)]
来完成层级结构的规划的.
- 其中
#[command(flatten)]
是将字命令提升一级, 相当于用子命令替换了#[command(flatten)]
所在的参数. #[command(subcomannd)]
和#[derive(Subcommand)]
组合完成子命令的创建.
同时可以看到的是 #[derive(Parser)]
和#[derive(Args)]
的使用.
在只有具体参数选项的结构中, 使用的是#[derive(Parser)]
, 比如login::Cmd
和import::Cmd
. Clap crate
的文档中对Parser
的解释就是
Parse command-line arguments into
Self
.
将参数解析到Self(我理解可以是enum或者struct)当中. 也就是最后需要完成参数解析了.
对Args
的解释是
Parse a set of arguments into a user-defined container.
Implementing this trait lets a parent container delegate argument parsing behavior to
Self
. with:
#[command(flatten)] args: ChildArgs
: Attribute can only be used with struct fields that implArgs
.Variant(ChildArgs)
: No attribute is used with enum variants that implArgs
.(适用当前account::Cmd的情况)
对Subcommand
的解释是
Parse a sub-command into a user-defined enum.
Implementing this trait lets a parent container delegate subcommand behavior to
Self
. with:
#[command(subcommand)] field: SubCmd
: Attribute can be used with either struct fields or enum variants that implSubcommand
.#[command(flatten)] Variant(SubCmd)
: Attribute can only be used with enum variants that implSubcommand
.
从两个官方给出的解释可以看到, Args
是解析参数集合到用户定义的容器中(只要求容器类型), Subcommand
是解析子命令到用户定义的枚举中(只能是枚举). 还有的不同是(这块还没理解到, 后面补充)
rust
#[command(flatten)]
args: ChildArgs --> ChildArgs必须是实现了Args的struct
#[command(flatten)]
Variant(SubCmd) --> SubCmd必须是实现了Subcommand的enum