Clap学习
本片内容主要参考clap的官方文档
在使用Rust
的库之前, 首先需要添加clap库:
cargo add clap --features derive
运行这个命令行会在Cargo.toml
中添加
clap = { version = "4.2.1", features = ["derive"] }
关于为什么要加features,可以阅读 Rust语言圣经中的内容.
或者可以直接手动在Cargo.toml
中添加clap库的配置.
从我添加的这个配置可以看到, 这篇文章是根据clap==4.2.1版本写的. 之前的版本我也不了解, 先不写了.
一.基础用法例子
use clap::Parser;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Name of the person to greet
#[arg(short, long)]
name: String,
/// Number of times to greet
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Hello {}!", args.name)
}
}
这个是官方文档中的例子, 这是使用derive
派生的方式实现.
从这个例子中可以看到, clap的使用方式是:
- 先创建一个
struct
, 其中的字段就是命令行的参数名称. - 给
struct
添加Parser
的派生. - 添加
command
, 为了控制命令行展示的行为, 也可以不添加. - 给参数添加
arg
, 为了控制单个参数的信息, 也可以不添加.不添加每个参数都是必填的 - 在
main
函数中解析参数(Args::parse()
)
在这个例子中可以看到command
, arg
, short
, long
, default_value_t
这些名字, 下来先了解一下这些名字的含义,和为什么要使用这些名词.
二. clap概念
Attributes
官方文档中所说的Attributes
是指
- #[derive(Debug, Parser)]
- #[command(author, version, about, long_about = None)]
- #[arg(short, long, default_value_t = 1)]
中使用 #[]
语法定义的类属性宏(目的是: 用于为目标添加自定义的属性).
这其中分为Raw attributes
和 Magic attributes
. 在Clap官方文档中有句话
Raw attributes are forwarded directly to the underlying clap builder. Any
Command
,Arg
, orPossibleValue
method can be used as an attribute.
说是raw attributes
会被转发给底层的clap builder
, 并且Command
等的方法会被用作attribute. 从文档中给的例子是
#[command(arg_required_else_help(true))] would translate to cmd.arg_required_else_help(true)
这里的arg_required_else_help
是command
实现的一个方法.
对于Magic attributes
文档中的描述是
Magic attributes have post-processing done to them, whether that is
- Providing of defaults
- Special behavior is triggered off of it
所以Magic attributes
是会提供默认值或引发特殊行为的方法.
综上总结就是,raw attributes
是普通的方法, 而Magic attributes
是有特殊行为的方法.magic是raw的升级.
command和arg
command
, arg
是Clap
实现的类属性宏. 他们的作用就是为影响命令行参数的行为和提示信息.
command
用来改变应用级别的行为,用来定义一个命令行界面. 比如整个应用的版本和作者, 上述提到的arg_required_else_help(没有参数就显示提示信息)方法.
arg
是所有参数的抽象表示, 用于为程序定义所有有效参数的选项和关系.
从这个定义看, Command
是包含Arg
的概念的. 先有一个命令行的界面内容, 里面才有Arg
参数. 而magic/raw attributes
则是控制每一个具体的功能项目.
三. Command
与Command
关联的raw attributes
和magic attributes
.
Raw Attributes
Magic Attributes
name = <expr>
未设置时,取crate name(Parser中), 变量名(Subcommand中)version [=<expr>]
启用但未设置值时, crate version. 未启用为空author [=<expr>]
启用但未设置值时, crate authors. 未启用为空about [=<expr>]
启用但未设置值时, crate description. 未启用时为Doc commentlong_about [=<expr>]
启用但未设置值时, 使用Doc comment. 未启用时没有值verbatim_doc_comment
在将doc注释转换为about/long_about时最小化预处理
四. Arg
Magic Attributes
id = <expr>
未设置时, 取struct中的字段名字,指定了就用指定名字value_parser [=<expr>]
未设置时, 根据类型使用value_parser!
的行为action [=<expr>]
未设置时, 使用ArgAction
的默认行为.help=<expr>
未设置时,使用文档注释内容- long_help
- verbatim_doc_comment
- short
Arg
的magic attributes
是设置每个参数的属性和功能.
五 如何设置
位置参数
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
name: Option<String>,
}
fn main() {
let cli = Cli::parse();
println!("name: {:?}", cli.name.as_deref());
}
name 只能接收一个参数值, 输入多个就会报错, ArgAction
的默认行为是Set
只能设置一个值, 如果想要收集多个值要将name改为name: Vec<String>
.
$ ./practice bob
>> name: Some("bob")
$ ./practice bob tom
>> error: unexpected argument 'tom' found
$ ./practice bob tom
>> name: ["bob", "tom"] <- 改成Vec<String>后
可选参数
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(short, long)]
name: Option<String>,
}
fn main() {
let cli = Cli::parse();
println!("name: {:?}", cli.name.as_deref());
}
文档例子中#[arg(short, long)]
的作用是为name
参数设置单字母选项和长选项. 设置#[arg]
后会将name
放在Option
选项中(变成了相当于关键字参数). 否则是Arguments
中.
$ ./practice -h <- 未加 #[arg(short, long)]
>> Usage: practice [NAME]
Arguments:
[NAME]
Options:
-h, --help Print help
-V, --version Print version
$ ./practice -h <- 加了 #[arg(short, long)]
>> Usage: practice [OPTIONS]
Options:
-n, --name <NAME>
-h, --help Print help
-V, --version Print version
结果是: 必须使用长/短选项才能设置值, 否则不能设置该参数值.
$ ./practice --name bob
>> name: Some("bob")
$ ./practice -n bob
>> name: Some("bob")
$ ./practice
>> name: None <- name的类型是Option<String>, 没有设置时就是None
$ ./practice bob
>> error: unexpected argument 'bob' found <- 意思没有bob这个参数
同样这里设置值的默认行为是ArgAction::Set
只能设置一个值, 如果想要收集多个值要将name改为name: Vec<String>
.
标志
标志是设置有和无(True/False
). 这里也可以设置为计数的模式, 看设置了多少次True
.
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(short, long)]
verbose: bool,
}
fn main() {
let cli = Cli::parse();
println!("verbose: {:?}", cli.verbose);
}
使用标志位的方式就是, 将元素的类型设置成布尔值, 但是布尔值的特性是, 只能被设置一次, 第二次设置时会报错.
$ ./practice --verbose
>> verbose: true
$ ./practice --verbose --verbose
>> error: the argument '--verbose' cannot be used multiple times
使用action = clap::ArgAction::Count
, 同时将元素类型设置为int可以对参数的数量进行计数.
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {<