arg用法
arg参数提示
cargo add clap -F derive
short短参数
- 可以使用
short='A'设置简短别名
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short)]
name: String,
// 需要使用单引号
#[arg(short='A')]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap -n <NAME> -A <AGE>
Options:
-n <NAME>
-A <AGE>
-h, --help Print help
long长参数
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long)]
name: String,
// 设置长参数别名
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME>
-A, --AGE-AAA <AGE>
-h, --help Print help
设置别名
不可见别名
alias单个别名
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 别名设置
#[arg(short, long, alias="VV1")]
name: String,
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME>
-A, --AGE-AAA <AGE>
-h, --help Print help
aliases多个别名
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 别名设置
#[arg(short, long, aliases=["V1", "V2"])]
name: String,
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME>
-A, --AGE-AAA <AGE>
-h, --help Print help
可见别名
visible_alias单个别名
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 别名设置
#[arg(short, long, visible_alias="VV1")]
name: String,
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME> [alias: --VV1]
-A, --AGE-AAA <AGE>
-h, --help Print help
visible_aliases多个别名
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 别名设置
#[arg(short, long, visible_aliases=["V1", "V2"])]
name: String,
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME> [aliases: --V1, --V2]
-A, --AGE-AAA <AGE>
-h, --help Print help
设置value_name
设置填入参数的显示内容
use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)]
struct MyCli {
// value_name设置
#[arg(short, long, value_name="Name")]
name: String,
#[arg(short='A', long="AGE-AAA", value_name="Age")]
age: String,
// 文件类型也可以
#[arg(short, long, value_name = "CONFIG.toml")]
config: PathBuf,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
Usage: test_clap --name <Name> --AGE-AAA <Age> --config <CONFIG.toml>
Options:
-n, --name <Name> # 变为了value_name值
-A, --AGE-AAA <Age> # 变为了value_name值
-c, --config <CONFIG.toml> # 变为了value_name值
-h, --help Print help
帮助排序display_order
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, display_order = 3)]
name: String,
#[arg(short, long, display_order = 1)]
age: String,
#[arg(short, long, display_order = 2)]
debug: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}-{}", cli.name, cli.age, cli.debug);
}
target/debug/test_clap -h
Usage: test_clap [OPTIONS] --name <NAME> --age <AGE>
Options:
-a, --age <AGE> # display_order=1
-d, --debug # display_order=2
-n, --name <NAME> # display_order=3
-h, --help Print help
参数分组help_heading
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, help_heading = "用户信息")]
name: String,
#[arg(short, long, help_heading = "用户信息")]
age: String,
#[arg(short, long, help_heading = "测试")]
debug: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
Usage: myapp [OPTIONS] --name <NAME> --age <AGE>
Options:
-h, --help Print help
用户信息:
-n, --name <NAME>
-a, --age <AGE>
测试:
-d, --debug
参数隐藏hide
设置
hide = true,命令行帮助不会显示,但是可以正常使用
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long)]
name: String,
#[arg(short, long)]
age: String,
#[arg(short, long, hide = true)]
debug: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}-{}", cli.name, cli.age, cli.debug);
}
Usage: test_clap --name <NAME> --age <AGE>
Options:
-n, --name <NAME>
-a, --age <AGE>
-h, --help Print help
设置help参数说明
使用斜杠说明
需要使用
///添加说明,-h/--help都使用一样的说明
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
/// 输入名字
#[arg(short, long)]
name: String,
/// 输入
/// 年龄
// 上面的是说明,我这个是注释
#[arg(short='A', long="AGE-AAA")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME> 输入名字
-A, --AGE-AAA <AGE> 输入 年龄
-h, --help Print help
设置-h说明help
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, help="这是名字")]
name: String,
#[arg(short='A', long="AGE-AAA", help="这是年龄")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME> 这是名字
-A, --AGE-AAA <AGE> 这是年龄
-h, --help Print help
设置--help说明long_help
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, help="这是名字", long_help="请输入你的名字")]
name: String,
#[arg(short='A', long="AGE-AAA", help="这是年龄", long_help="请输入你的年龄")]
age: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
cargo run -- -h
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME> 这是名字
-A, --AGE-AAA <AGE> 这是年龄
-h, --help Print help (see more with '--help')
cargo run -- --help
Usage: test_clap --name <NAME> --AGE-AAA <AGE>
Options:
-n, --name <NAME>
请输入你的名字
-A, --AGE-AAA <AGE>
请输入你的年龄
-h, --help
Print help (see a summary with '-h')
设置默认值
未输入选项
default_value运行检查
字符串字面量
- 接受 字符串字面量 (
&str) - 值在运行时通过
FromStr解析成目标类型 - 如果解析失败,运行时 panic(编译期不检查)
- 适用于需要动态字符串的场景(如从环境变量拼接)
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, default_value = "Tom")]
name: String,
#[arg(short, long, default_value = "32")]
age: i32, // 字符串 "32" 在运行时解析成 i32
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age + 2);
}
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME> [default: Tom]
-a, --age <AGE> [default: 32]
-h, --help Print help
default_value_t编译期检查
- 接受目标类型的直接值(age这里是
i32而不是&str) - 编译期类型检查,类型不匹配直接编译失败
- 更安全,IDE 能自动补全和类型推断
- 适用于静态常量场景
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 需要填写对应的类型
#[arg(short, long, default_value_t = "Tom".to_string())]
name: String,
// 需要填写对应的类型
#[arg(short, long, default_value_t = 32)]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age + 2);
}
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME> [default: Tom]
-a, --age <AGE> [default: 32]
-h, --help Print help
输入选项没有输入值
default_missing_value运行检查
#[arg(short, long, default_value = "Tom", default_missing_value = "Tom1")]
name: String,
./app # default_value值Tom生效
./app --name # default_missing_value值Tom1生效
./app -name Bob # 设置值Bob生效
default_missing_value_t编译器检查
#[arg(short, long, default_value_t = 18, default_missing_value_t = 30)]
age: i32,
./app # default_value_t值18生效
./app --age # default_missing_value_t值30生效
./app --age 35 # 设置值35生效
隐藏默认值
hide_default_value
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 设置默认值隐藏hide_default_value=true
#[arg(short, long, default_value_t = "Tom".to_string(), hide_default_value=true)]
name: String,
// 需要填写对应的类型
#[arg(short, long, default_value_t = 32)]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age + 2);
}
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME>
-a, --age <AGE> [default: 32]
-h, --help Print help
环境变设置默认值
env
clap需要开启env的features
- 优先级
| 场景 | 最终值 |
|---|---|
--age 30 |
30(命令行最高) |
MY_AGE=20 cargo run |
20(环境变量次之) |
cargo run |
20(默认值兜底) |
env配和default_value
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, default_value = "Tom", env = "MY_NAME")]
name: String,
#[arg(short, long, default_value = "20", env = "MY_AGE")]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME> [env: MY_NAME=] [default: Tom]
-a, --age <AGE> [env: MY_AGE=] [default: 20]
-h, --help Print help
env配和default_value_t
default_value_t和env配合使用时,default_value_t的值类型必须与字段定义的类型一致。这是default_value_t的核心设计——编译期类型检查
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, default_value_t = "Tom".to_string(), env = "MY_NAME")]
name: String,
#[arg(short, long, default_value_t = 20, env = "MY_AGE")]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME> [env: MY_NAME=] [default: Tom]
-a, --age <AGE> [env: MY_AGE=11] [default: 20]
-h, --help Print help
hide_env隐藏env字段提示
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(
short,
long,
default_value = "Tom",
env = "MY_NAME",
hide_env = true
)]
name: String,
#[arg(
short,
long,
default_value = "20",
env = "MY_AGE",
hide_env = true
)]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
target/debug/test_clap -h
Usage: test_clap [OPTIONS]
Options:
-n, --name <NAME> [default: Tom]
-a, --age <AGE> [default: 20]
-h, --help Print help
hide_env_values隐藏环境变量值
hide_env_values用于隐藏环境变量的实际值,防止敏感信息(如密码、Token)泄露到帮助文档中
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
/// 普通配置,可以显示
#[arg(long, env = "PORT", default_value_t = 8080)]
port: u16,
/// 敏感信息,隐藏值
#[arg(long, env = "API_KEY", hide_env_values = true)]
api_key: String,
/// 也敏感,隐藏
#[arg(long, env = "DB_PASSWORD", hide_env_values = true)]
db_password: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
PORT=3000 API_KEY=secret DB_PASSWORD=123 cargo run -- --help
Usage: test_clap [OPTIONS] --api-key <API_KEY> --db-password <DB_PASSWORD>
Options:
--port <PORT> 普通配置,可以显示 [env: PORT=3000] [default: 8080]
--api-key <API_KEY> 敏感信息,隐藏值 [env: API_KEY]
--db-password <DB_PASSWORD> 也敏感,隐藏 [env: DB_PASSWORD]
-h, --help Print help
设置参数要求
必填参数required
如果
default_value_t存在,则required可以省略,因为默认值保证参数总有值
- 参数是否必须提供:不仅取决于
required,更取决于字段类型和是否有默认值。 - 真正可选的参数:请使用
Option<T>或添加default_value
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// name为必填参数
#[arg(short, long, required = true)]
name: String,
// age也为必填参数
#[arg(short, long)]
age: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {}-{}", cli.name, cli.age);
}
可选参数
使用Option<T> 类型
- 用户提供时,
age为Some(value);不提供时为None。 required自动被忽略(因为Option已经表示了可选性)。
#[arg(short, long)]
age: Option<i32>,
设置默认值
- 用户不提供时,
age取默认值。 - 使用
default_value_t或者default_value
#[arg(short, long, default_value_t = 18)]
age: i32,
枚举值(限定可选值)
// 需要导入ValueEnum
use clap::{Parser, ValueEnum};
#[derive(Debug, Clone, ValueEnum)]
enum LogLevel {
Debug,
Info,
Warn,
Error,
}
#[derive(Parser, Debug)]
struct MyCli {
// 需要定义value_enum
// 设置default_value_t默认值
#[arg(short, long, value_enum, default_value_t = LogLevel::Info)]
log: LogLevel
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {:?}", cli.log);
}
Usage: test_clap [OPTIONS]
Options:
-l, --log <LOG> [default: info] [possible values: debug, info, warn, error]
-h, --help Print help
多值参数
value_delimiter 单参数-多值
-i x,xx,xxx传值
分隔符
| 分隔符 | 问题 |
|---|---|
, |
通用,但如果值本身含逗号会冲突 |
: |
Unix 路径常用,安全 |
| |
shell 需要转义 |,麻烦 |
(空格) |
shell 会先把空格拆成多个参数,需要加引号 "a b c" |
#[arg(short, long, value_delimiter = ':')]
paths: Vec<String>,
#[arg(short, long, value_delimiter = '|')]
items: Vec<String>,
#[arg(short, long, value_delimiter = ' ')] // 空格也可以
words: Vec<String>,
案例
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// value_delimiter='设置分隔符'
#[arg(short, long, value_delimiter=',')]
item: Vec<String>
}
fn main() {
let cli = MyCli::parse();
println!("cli.item: {:?}", cli.item);
}
target/debug/test_clap -i 1,2,3,4
cli.item: ["1", "2", "3", "4"]
num_args重复传参
item: Vec<String>自动开启了ArgAction::Append,所以可多次调用-inum_args控制
-i xx xx xx的参数个数
控制范围
#[arg(short, long, num_args = 1..)] // 传入1个获取多个
#[arg(short, long, num_args = 2..=4)] // 必须传 2 到 4 个
#[arg(short, long, num_args = 0..=3)] // 最多 3 个
#[arg(short, long, num_args = 3)] // 必须恰好 3 个
案例
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// num_args设置-i中需要填写多少个参数的个数
#[arg(short, long, num_args=3)]
item: Vec<String>
}
fn main() {
let cli = MyCli::parse();
println!("cli.item: {:?}", cli.item);
}
Usage: test_clap [OPTIONS]
Options:
-i, --item <ITEM> <ITEM> <ITEM>
-h, --help Print help
target/debug/test_clap -i 1 2 3 # num_args=3表示必须传入3个值
cli.item: ["1", "2", "3"]
允许负数值
clap::ArgAction
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, allow_hyphen_values = true)]
offset: i32,
}
fn main() {
let cli = MyCli::parse();
println!("cli.offset: {}", cli.offset);
}
target/debug/test_clap -o -30
cli.offset: -30
设置clap::ArgAction
action设置的是"用户传参时,值怎么变":Set是直接赋值,SetTrue是变 true,Count是累加,Append是追加到列表。它决定了命令行参数到 Rust 字段的映射规则
Count计数参数(-vvv)
作用是用同一个 flag 的重复次数来控制级别/程度,常见于控制日志详细程度。
案例
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
/// 详细程度(-v, -vv, -vvv)
// 设置action为clap::ArgAction::Count
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
}
fn main() {
let cli = MyCli::parse();
// cli.verbose返回次数
match cli.verbose {
0 => println!("只显示错误"),
1 => println!("显示警告 + 错误"),
2 => println!("显示信息 + 警告 + 错误"),
3 => println!("显示调试信息"),
_ => println!("全部调试(包括 trace)"),
}
}
cargo run -- # verbose = 0,只显示错误
cargo run -- -v # verbose = 1,显示警告
cargo run -- -vv # verbose = 2,显示信息
cargo run -- -vvv # verbose = 3,显示调试
cargo run -- -vvvv # verbose = 4,全部
场景使用
use clap::Parser;
use tracing::Level;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
}
fn main() {
let cli = MyCli::parse();
// 控制日志显示级别
let level = match cli.verbose {
0 => Level::ERROR,
1 => Level::WARN,
2 => Level::INFO,
3 => Level::DEBUG,
_ => Level::TRACE,
};
tracing_subscriber::fmt()
.with_max_level(level)
.init();
tracing::info!("应用启动");
}
Set默认值
默认值, 允许出现一次
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, action=clap::ArgAction::Set)]
name: String
}
fn main() {
let cli = MyCli::parse();
println!("cli.name: {:?}", cli.name);
}
target/debug/test_clap --name Tom
cli.name: "Tom"
# 错误
# target/debug/test_clap --name Tom --name Bob
# target/debug/test_clap --name Tom Bob
Append显式追加到 Vec
可以多次出现
-i调用
// 默认开启了action = clap::ArgAction::Append
#[arg(short, long)]
files: Vec<String>,
基础使用
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// num_args设置-i参数个数
#[arg(short, long, action=clap::ArgAction::Append)]
item: Vec<String>
}
fn main() {
let cli = MyCli::parse();
println!("cli.item: {:?}", cli.item);
}
Usage: test_clap [OPTIONS]
Options:
-i, --item <ITEM>
-h, --help Print help
target/debug/test_clap -i 1 -i 22 -i 33
cli.item: ["1", "22", "33"]
结合num_args
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// num_args设置-i参数个数
#[arg(short, long, action=clap::ArgAction::Append, num_args = 2)]
item: Vec<String>
}
fn main() {
let cli = MyCli::parse();
println!("cli.item: {:?}", cli.item);
}
Usage: test_clap [OPTIONS]
Options:
-i, --item <ITEM> <ITEM>
-h, --help Print help
target/debug/test_clap -i 1 2 -i 3 4
cli.item: ["1", "2", "3", "4"]
布尔值设置
默认SetTrue
默认值是
false,--is_test激活了才是true
action=clap::ArgAction::SetTrue
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// 默认是action=clap::ArgAction::SetTrue模式
#[arg(short, long)]
is_test: bool
}
fn main() {
let cli = MyCli::parse();
println!("cli.is_test: {:?}", cli.is_test);
}
# 默认false值
target/debug/test_clap
cli.is_test: false
# 输入后才是true
target/debug/test_clap --is-test
cli.is_test: true
相反设置SetFalse
效果不输入时
true,输入后变为false
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, action=clap::ArgAction::SetFalse)]
skip: bool
}
fn main() {
let cli = MyCli::parse();
println!("cli.skip: {:?}", cli.skip);
}
# 默认true值
target/debug/test_clap
cli.skip: true
# 输入后变为false
target/debug/test_clap --skip`
cli.skip: false
参数关系
参数依赖requires
设置单个依赖
使用
-p、--password时,必须传入-u、--username
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long)]
username: String,
/// 必须和 --username 一起使用
#[arg(short, long, requires = "username")]
password: String,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
Usage: test_clap --username <USERNAME> --password <PASSWORD>
Options:
-u, --username <USERNAME>
-p, --password <PASSWORD> 必须和 --username 一起使用
-h, --help Print help
设置多个依赖
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long)]
username: Option<String>,
#[arg(short, long)]
password: Option<String>,
/// 必须和 --username/--password 一起使用
#[arg(short, long, requires = "username", requires = "password")]
login: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
Usage: test_clap [OPTIONS]
Options:
-u, --username <USERNAME>
-p, --password <PASSWORD>
-l, --login 必须和 --username/--password 一起使用
-h, --help Print help
参数互斥
conflicts_with
conflicts_with是两两互斥
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
/// 输出 JSON 格式
#[arg(long, conflicts_with = "pretty")]
json: bool,
/// 美化输出
#[arg(long, conflicts_with = "json")]
pretty: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
# 单独使用json
target/debug/test_clap --json
cli: MyCli { json: true, pretty: false }
# 单独使用pretty
target/debug/test_clap --pretty
cli: MyCli { json: false, pretty: true }
# 报错
target/debug/test_clap --json --pretty
conflicts_with_all
用于一个参数同时与多个参数互斥
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
/// 简洁模式,与其他详细模式互斥
#[arg(short, long, conflicts_with_all = ["verbose", "debug", "trace"])]
quiet: bool,
#[arg(short, long)]
verbose: bool,
#[arg(long)]
debug: bool,
#[arg(long)]
trace: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
Usage: test_clap [OPTIONS]
Options:
-q, --quiet 简洁模式,与其他详细模式互斥
-v, --verbose
--debug
--trace
-h, --help Print help
# 单独用
cargo run -- --quiet
cargo run -- --verbose
cargo run -- --debug
# quiet 和任何详细模式冲突
cargo run -- --quiet --verbose # 报错
cargo run -- --quiet --debug # 报错
cargo run -- --quiet --trace # 报错
独占类型
exclusive
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
// -q/--quiet不能和其他任何参数混用
#[arg(short, long, exclusive = true)]
quiet: bool,
#[arg(short, long)]
verbose: bool,
#[arg(short, long)]
debug: bool,
#[arg(short, long)]
trace: bool,
}
fn main() {
let cli = MyCli::parse();
println!("cli: {:?}", cli);
}
target/debug/test_clap -v -d
cli: MyCli { quiet: false, verbose: true, debug: true, trace: false }
# 报错,不能和-q使用
target/debug/test_clap -v -d -q
value_parser参数验证
value_parser!(T)
基础类型转换
use clap::Parser;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, value_parser = clap::value_parser!(u16))]
port: u16,
#[arg(short, long, value_parser = clap::value_parser!(f64))]
threshold: f64,
#[arg(short, long, value_parser = clap::value_parser!(bool))]
debug: bool,
}
范围验证
#[derive(Parser, Debug)]
struct MyCli {
// 端口号范围 1024-65535
#[arg(short, long, value_parser = clap::value_parser!(u16).range(1024..=65535))]
port: u16,
// 重试次数 1-10
#[arg(short, long, value_parser = clap::value_parser!(u8).range(1..=10))]
retry: u8,
// 浮点范围 0.0-1.0
#[arg(long, value_parser = clap::value_parser!(f64).range(0.0..=1.0))]
ratio: f64,
}
网络类型
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddr};
#[derive(Parser, Debug)]
struct MyCli {
#[arg(long, value_parser = clap::value_parser!(Ipv4Addr))]
ip: Ipv4Addr,
#[arg(long, value_parser = clap::value_parser!(SocketAddrV4))]
bind: SocketAddrV4,
#[arg(long, value_parser = clap::value_parser!(SocketAddr))]
addr: SocketAddr,
}
路径类型
use std::path::PathBuf;
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, value_parser = clap::value_parser!(PathBuf))]
config: PathBuf,
#[arg(short, long, value_parser = clap::value_parser!(PathBuf))]
output: Option<PathBuf>,
}
字符串验证
#[derive(Parser, Debug)]
struct MyCli {
// String 基本不需要 value_parser,但显式写也可以
#[arg(short, long, value_parser = clap::value_parser!(String))]
name: String,
// OsString 用于非 UTF-8 路径
#[arg(short, long, value_parser = clap::value_parser!(std::ffi::OsString))]
path: std::ffi::OsString,
}
自定义类型(需实现 FromStr)
use clap::Parser;
use std::str::FromStr;
#[derive(Debug, Clone)]
struct Color(u8, u8, u8);
impl FromStr for Color {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let v: Vec<u8> = s.split(',')
.map(|p| p.parse().map_err(|_| "无效数字"))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.to_string())?;
if v.len() != 3 {
return Err("格式必须是 R,G,B".to_string());
}
Ok(Color(v[0], v[1], v[2]))
}
}
#[derive(Parser, Debug)]
struct MyCli {
#[arg(short, long, value_parser = clap::value_parser!(Color))]
color: Color,
}
容器类型
#[derive(Parser, Debug)]
struct MyCli {
// 多次传参收集
#[arg(short, long, value_parser = clap::value_parser!(u32))]
ports: Vec<u32>,
// 可选参数
#[arg(short, long, value_parser = clap::value_parser!(String))]
name: Option<String>,
}
自定义验证规则
案例
use clap::Parser;
// 自定义解释器
fn parse_positive(s: &str) -> Result<u32, String> {
let n: u32 = s.parse().map_err(|_| "Not a number")?;
if n > 0 { Ok(n) } else { Err("Must be positive".into()) }
}
#[derive(Parser, Debug)]
struct Cli {
// parse_positive传入的是&str
#[arg(long, value_parser = parse_positive)]
age: u32,
#[arg(long, value_parser = parse_positive, num_args = 1..)]
ages: Vec<u32>,
}
fn main() {
let cli = Cli::parse();
println!("age: {}", cli.age);
println!("ages: {}", cli.ages);
}
验证规则
cargo run -- --ages 10,20,30
# "10,20,30" 会被拆成 "10", "20", "30",分别调用 parse_positive
命令行输入: --ages 10 --ages 20 --ages 30
↓ ↓
parse_positive("10") → Ok(10)
parse_positive("20") → Ok(20)
parse_positive("30") → Ok(30)
↓
ages: Vec<u32> = [10, 20, 30]

浙公网安备 33010602011771号