Rust命令行参数解析库clap-adapters的使用,为clap提供扩展适配器和自定义参数处理功能
Rust命令行参数解析库clap-adapters的使用,为clap提供扩展适配器和自定义参数处理功能
clap-adapters
是为clap
库提供的适配器类型,用于声明式加载配置。
任何实现了FromStr
特性的类型都可以用在clap
的派生结构体中,这意味着任何可以放入fn(&str) -> Result<T, Error>
函数的逻辑都可以在解析时运行。这对于声明式选择配置文件或做其他很酷的事情特别有用。
基本使用示例
以下示例展示了如何使用clap-adapters
来解析JSON配置文件:
use clap::Parser;
use clap_adapters::prelude::*;
#[derive(Debug, Parser)]
struct Cli {
/// 任意Json配置文件的路径
#[clap(long)]
config: PathTo<JsonOf<serde_json::Value>>,
}
fn main() {
// 在临时目录中创建配置文件
let config_dir = tempfile::tempdir()?;
let config_path = config_dir.path().join("config.json");
let config_path_string = config_path.display().to_string();
// 将测试配置{"hello":"world"}写入配置文件
let config = serde_json::json!({"hello": "world"});
let config_string = serde_json::to_string(&config)?;
std::fs::write(&config_path, &config_string)?;
// 解析我们的CLI,将配置文件路径传递给--config
let cli = Cli::parse_from(["app", "--config", &config_path_string]);
let data = cli.config.data();
// 我们应该期望得到的值与写入配置的值匹配
assert_eq!(data, &serde_json::json!({"hello":"world"}));
}
扩展clap-adapters
您可以通过定义实现此crate中特性的新类型来实现额外的可组合适配器。例如,通过实现FromReader
,您可以定义一个可以从文件路径构造自身的适配器,将您的适配器嵌套到PathTo<T>
中,如PathTo<YourAdapter>
。
完整自定义示例
下面是一个更完整的示例,展示了如何自定义适配器:
use clap::Parser;
use clap_adapters::{prelude::*, JsonOf, PathTo};
use serde::Deserialize;
use std::path::PathBuf;
use std::str::FromStr;
// 自定义配置结构体
#[derive(Debug, Deserialize)]
struct AppConfig {
server: String,
port: u16,
}
// 自定义适配器
struct ConfigAdapter(Result<AppConfig, String>);
impl FromStr for ConfigAdapter {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let path = PathBuf::from(s);
let contents = std::fs::read_to_string(&path)
.map_err(|e| format!("Failed to read config file: {}", e))?;
let config = serde_json::from_str::<AppConfig>(&contents)
.map_err(|e| format!("Failed to parse config: {}", e))?;
Ok(ConfigAdapter(Ok(config)))
}
}
#[derive(Debug, Parser)]
struct Cli {
/// 自定义配置文件路径
#[clap(long)]
config: PathTo<JsonOf<ConfigAdapter>>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建临时目录和配置文件
let config_dir = tempfile::tempdir()?;
let config_path = config_dir.path().join("app_config.json");
// 写入示例配置
let config_content = r#"{"server": "example.com", "port": 8080}"#;
std::fs::write(&config_path, config_content)?;
// 解析命令行参数
let cli = Cli::parse_from(["app", "--config", config_path.to_str().unwrap()]);
// 获取配置数据
if let JsonOf(ConfigAdapter(Ok(config))) = cli.config.data() {
println!("Server: {}", config.server);
println!("Port: {}", config.port);
}
Ok(())
}
这个示例展示了:
- 如何定义自定义配置结构体
AppConfig
- 如何创建自定义适配器
ConfigAdapter
- 如何实现
FromStr
特性来解析配置文件 - 如何将自定义适配器与
PathTo
和JsonOf
组合使用
安装和使用
要使用这个crate,可以通过以下命令添加到您的项目中:
cargo add clap-adapters
或者在Cargo.toml中添加:
[dependencies]
clap-adapters = "0.2.2"
1 回复
Rust命令行参数解析库clap-adapters使用指南
clap-adapters
是一个为Rust命令行参数解析库clap
提供扩展功能的库,它添加了适配器和自定义参数处理功能,增强了clap
的灵活性。
主要功能
- 提供多种参数适配器
- 支持自定义参数处理
- 简化复杂参数配置
- 增强错误处理能力
安装
在Cargo.toml
中添加依赖:
[dependencies]
clap = { version = "4.0", features = ["derive"] }
clap-adapters = "0.1"
基本使用方法
1. 使用预定义适配器
use clap::{Parser, Subcommand};
use clap_adapters::prelude::*;
#[derive(Parser)]
struct Args {
#[clap(adapter = Trim)]
name: String,
#[clap(adapter = Lowercase)]
category: String,
#[clap(adapter = ParseNumber)]
count: u32,
}
fn main() {
let args = Args::parse();
println!("Name: {}, Category: {}, Count: {}", args.name, args.category, args.count);
}
2. 自定义适配器
use clap::{Parser, Subcommand};
use clap_adapters::{Adapter, AdapterResult};
struct Capitalize;
impl Adapter for Capitalize {
type Target = String;
fn adapt(&self, input: &str) -> AdapterResult<Self::Target> {
if input.is_empty() {
return Err("Input cannot be empty".into());
}
let mut chars = input.chars();
let first = chars.next().unwrap().to_uppercase().collect::<String>();
let rest = chars.collect::<String>();
Ok(format!("{}{}", first, rest))
}
}
#[derive(Parser)]
struct Args {
#[clap(adapter = Capitalize)]
username: String,
}
fn main() {
let args = Args::parse();
println!("Username: {}", args.username); // 输入"john"会输出"John"
}
3. 组合适配器
use clap::Parser;
use clap-adapters::{prelude::*, AdapterChain};
#[derive(Parser)]
struct Args {
#[clap(adapter = AdapterChain::new()
.add(Trim)
.add(Lowercase)
.add(Capitalize))]
city: String,
}
内置适配器
clap-adapters
提供了一些常用的内置适配器:
Trim
: 去除字符串两端的空白字符Lowercase
: 转换为小写Uppercase
: 转换为大写ParseNumber
: 解析为数字类型ParseBool
: 解析为布尔值Split
: 按分隔符分割字符串Collect
: 收集多个值到集合
高级用法
自定义错误处理
use clap_adapters::{Adapter, AdapterResult};
struct EvenNumber;
impl Adapter for EvenNumber {
type Target = i32;
fn adapt(&self, input: &str) -> AdapterResult<Self::Target> {
let num = input.parse::<i32>()?;
if num % 2 == 0 {
Ok(num)
} else {
Err("Number must be even".into())
}
}
}
复杂参数处理
use clap::Parser;
use clap_adapters::{prelude::*, AdapterChain};
use serde_json::Value;
#[derive(Parser)]
struct ConfigArgs {
#[clap(
long,
adapter = AdapterChain::new()
.add(Trim)
.add(ParseJson)
)]
config: Value,
}
完整示例代码
下面是一个结合了多种功能的完整示例:
use clap::Parser;
use clap_adapters::{prelude::*, Adapter, AdapterResult, AdapterChain};
use serde_json::Value;
// 自定义适配器 - 将字符串转为大写并添加前缀
struct PrefixAdapter;
impl Adapter for PrefixAdapter {
type Target = String;
fn adapt(&self, input: &str) -> AdapterResult<Self::Target> {
Ok(format!("USER_{}", input.to_uppercase()))
}
}
// 主命令参数结构体
#[derive(Parser, Debug)]
#[command(name = "app", version = "1.0", about = "clap-adapters演示程序")]
struct Cli {
// 使用预定义Trim适配器
#[clap(short, long, adapter = Trim)]
name: String,
// 使用预定义ParseNumber适配器
#[clap(short, long, adapter = ParseNumber)]
age: u32,
// 使用自定义适配器
#[clap(short, long, adapter = PrefixAdapter)]
id: String,
// 使用适配器链
#[clap(
long,
adapter = AdapterChain::new()
.add(Trim)
.add(Lowercase)
)]
city: String,
// 复杂参数处理
#[clap(
long,
adapter = AdapterChain::new()
.add(Trim)
.add(ParseJson)
)]
config: Option<Value>,
}
fn main() {
let args = Cli::parse();
println!("解析后的参数: {:?}", args);
println!("\n示例用法:");
println!("cargo run -- --name \" John Doe \" --age 30 --id johndoe --city \"NEW YORK\" --config '{\"key\":\"value\"}'");
}
注意事项
- 适配器会按照添加顺序依次执行
- 错误消息会传递给clap的错误处理系统
- 复杂的适配器链可能会影响性能
- 适配器只能用于字段参数,不能用于命令或子命令
clap-adapters
为clap
提供了更强大的参数处理能力,特别适合需要复杂参数转换和验证的场景。