三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

arg用法

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 -- -hUsage: 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 -- -hUsage: 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 -- -hUsage: 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 -- -hUsage: 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 -- -hUsage: 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 -- --helpUsage: test_clap --name <NAME> --AGE-AAA <AGE>Options:-n, --name <NAME>请输入你的名字-A, --AGE-AAA <AGE>请输入你的年龄-h, --helpPrint 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需要开启envfeatures

  • 优先级
场景 最终值
--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_tenv 配合使用时,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 -- --helpUsage: 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> 类型

  • 用户提供时,ageSome(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,所以可多次调用-i

num_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]
← 返回列表