Rust命令行参数解析库paw的使用,简化终端应用开发与参数处理
Rust命令行参数解析库paw的使用,简化终端应用开发与参数处理
paw是一个用于main函数的命令行参数解析抽象库。
Paw的目标是展示C语言将参数传递给main的想法并不糟糕,只是需要一些氧化来使其与Rust一起工作。
Paw定义了一个特性、一个过程宏和一个示例实现,当组合使用时,允许您将完全解析的参数传递给main。不再需要记住在CLI中解析参数要调用哪些方法。相反,paw使命令行解析感觉像是一等公民。
示例
#[paw::main]
fn main(args: paw::Args) {
for arg in args {
println!("{:?}", arg);
}
}
安装
$ cargo add paw
安全性
此crate使用#![deny(unsafe_code)]
确保所有内容都以100%安全Rust实现。
常见问题解答
Paw如何工作?
paw::main
属性允许fn main
接受任何实现paw::ParseArgs
特性的参数。paw::ParseArgs
实现一个方法:parse_args
,它返回一个Result<Self>
。
生成的任何错误都会从fn main
返回,返回的Result
类型控制如何打印它们。
与C的关系是什么?
在C的运行时中,命令行参数作为"参数数量"(argc
)和"参数列表"(argv
)的组合传递:
int main(int argc, char **argv) {
for(i = 1; i < argc; i++) {
printf("%s",argv[i]);
}
return 0;
}
在Rust中,这将转换为参数的迭代器,这正是std::env::Args
提供的,通过paw::Args
在paw
中包装。
Paw的未来是什么?
Paw是CLI工作组的一个实验,旨在为每个人提供更好的命令行体验。我们的假设是,通过将命令行解析移动到fn main
,Rust的命令行体验可以变得更加直观和易于使用。
我们希望收集人们使用此功能的反馈,并了解如何与现有库集成。这将需要时间,我们可能会在此过程中更改一些内容。
如果这个实验证明是成功的,我们可能会通过RFC流程将Paw提供的功能正式化到Rust本身中。但情况尚未如此,所以现在:我们希望您喜欢Paw,并且我们很乐意听取您使用它的经验!
许可证
MIT OR Apache-2.0
完整示例代码
// 引入paw库
use paw::ParseArgs;
// 使用paw::main属性宏
#[paw::main]
fn main(args: paw::Args) {
// 遍历所有命令行参数
for (index, arg) in args.enumerate() {
// 打印每个参数的索引和值
println!("参数 {}: {:?}", index, arg);
}
}
要运行此程序,首先需要在Cargo.toml中添加依赖:
[dependencies]
paw = "1.0.0"
然后可以使用以下命令运行程序:
cargo run -- arg1 arg2 arg3
输出将会是:
参数 0: "arg1"
参数 1: "arg2"
参数 2: "arg3"
Rust命令行参数解析库paw的使用指南
概述
paw是一个轻量级的Rust命令行参数解析库,专注于简化终端应用的开发和参数处理流程。它通过过程宏提供直观的API,让开发者能够快速定义和解析命令行参数。
安装方法
在Cargo.toml中添加依赖:
[dependencies]
paw = "1.0"
paw-attributes = "1.0"
基本使用方法
1. 定义命令行参数结构体
use paw_attributes::*;
#[derive(PawStruct)]
struct Args {
/// 输入文件路径
#[paw(short = "i", long = "input")]
input: String,
/// 输出文件路径
#[paw(short = "o", long = "output")]
output: Option<String>,
/// 详细输出模式
#[paw(short = "v", long = "verbose")]
verbose: bool,
/// 处理次数
#[paw(short = "c", long = "count")]
count: u32,
}
2. 在主函数中使用
#[paw::main]
fn main(args: Args) {
println!("输入文件: {}", args.input);
if let Some(output) = args.output {
println!("输出文件: {}", output);
}
if args.verbose {
println!("详细模式已启用");
}
println!("处理次数: {}", args.count);
}
高级功能示例
嵌套子命令
#[derive(PawStruct)]
enum Command {
/// 创建新项目
Create {
/// 项目名称
name: String,
/// 项目模板
#[paw(short = "t")]
template: Option<String>,
},
/// 构建项目
Build {
/// 发布模式
#[paw(short = "r", long = "release")]
release: bool,
},
}
#[derive(PawStruct)]
struct Args {
#[paw(subcommand)]
cmd: Command,
}
#[paw::main]
fn main(args: Args) {
match args.cmd {
Command::Create { name, template } => {
println!("创建项目: {}", name);
if let Some(t) = template {
println!("使用模板: {}", t);
}
}
Command::Build { release } => {
if release {
println!("发布模式构建");
} else {
println!("调试模式构建");
}
}
}
}
数组参数处理
#[derive(PawStruct)]
struct Args {
/// 要处理的文件列表
#[paw(short = "f", long = "files")]
files: Vec<String>,
}
#[paw::main]
fn main(args: Args) {
for file in args.files {
println!("处理文件: {}", file);
}
}
错误处理
paw会自动生成帮助信息和错误提示:
// 当用户输入无效参数时,会自动显示帮助信息
// 例如:cargo run -- --help
完整示例
use paw_attributes::*;
#[derive(PawStruct)]
struct AppArgs {
/// 配置文件路径
#[paw(short = "c", long = "config")]
config: Option<String>,
/// 日志级别
#[paw(short = "l", long = "log-level")]
log_level: String,
/// 要处理的数据文件
#[paw(short = "d", long = "data")]
data_files: Vec<String>,
}
#[paw::main]
fn main(args: AppArgs) -> Result<(), Box<dyn std::error::Error>> {
// 应用逻辑
println!("日志级别: {}", args.log_level);
for file in args.data_files {
println!("处理数据文件: {}", file);
}
Ok(())
}
优势特点
- 类型安全:所有参数都有明确的类型
- 自动生成帮助文档
- 支持子命令和嵌套结构
- 简洁的API设计
- 良好的错误提示
通过paw库,开发者可以快速构建功能完善、用户友好的命令行应用程序。
完整示例demo
//! 完整的paw命令行参数解析示例
//! 演示了paw库的主要功能特性
use paw_attributes::*;
use std::path::PathBuf;
/// 应用配置参数结构体
#[derive(PawStruct, Debug)]
struct Config {
/// 配置文件路径
#[paw(short = "c", long = "config", help = "指定配置文件路径")]
config_file: Option<PathBuf>,
/// 日志级别
#[paw(short = "l", long = "log-level", default = "info", help = "设置日志级别")]
log_level: String,
/// 启用调试模式
#[paw(short = "d", long = "debug", help = "启用调试模式")]
debug: bool,
}
/// 文件处理命令
#[derive(PawStruct, Debug)]
enum FileCommand {
/// 压缩文件
Compress {
/// 输入文件
#[paw(short = "i", long = "input", help = "输入文件路径")]
input: PathBuf,
/// 输出文件
#[paw(short = "o", long = "output", help = "输出文件路径")]
output: Option<PathBuf>,
/// 压缩级别
#[paw(short = "l", long = "level", default = "6", help = "压缩级别(1-9)")]
level: u8,
},
/// 解压文件
Extract {
/// 压缩文件
#[paw(short = "f", long = "file", help = "压缩文件路径")]
file: PathBuf,
/// 输出目录
#[paw(short = "d", long = "directory", help = "解压输出目录")]
directory: Option<PathBuf>,
/// 覆盖已存在文件
#[paw(short = "o", long = "overwrite", help = "覆盖已存在文件")]
overwrite: bool,
},
}
/// 主命令行参数结构体
#[derive(PawStruct, Debug)]
struct CliArgs {
/// 全局配置
#[paw(flatten)]
config: Config,
/// 子命令
#[paw(subcommand)]
command: FileCommand,
/// 要处理的文件列表
#[paw(short = "f", long = "files", help = "要处理的文件列表")]
files: Vec<PathBuf>,
/// 线程数量
#[paw(short = "t", long = "threads", default = "4", help = "工作线程数量")]
threads: usize,
}
/// 主函数
#[paw::main]
fn main(args: CliArgs) -> Result<(), Box<dyn std::error::Error>> {
// 打印配置信息
println!("=== 应用配置 ===");
if let Some(config_path) = &args.config.config_file {
println!("配置文件: {}", config_path.display());
}
println!("日志级别: {}", args.config.log_level);
println!("调试模式: {}", args.config.debug);
println!("线程数量: {}", args.threads);
// 处理文件列表
if !args.files.is_empty() {
println!("\n=== 文件列表 ===");
for file in &args.files {
println!("处理文件: {}", file.display());
}
}
// 处理子命令
println!("\n=== 执行命令 ===");
match &args.command {
FileCommand::Compress { input, output, level } => {
println!("压缩命令:");
println!(" 输入文件: {}", input.display());
if let Some(output_path) = output {
println!(" 输出文件: {}", output_path.display());
}
println!(" 压缩级别: {}", level);
// 这里添加实际的压缩逻辑
compress_file(input, output.as_ref(), *level)?;
}
FileCommand::Extract { file, directory, overwrite } => {
println!("解压命令:");
println!(" 压缩文件: {}", file.display());
if let Some(dir) = directory {
println!(" 输出目录: {}", dir.display());
}
println!(" 覆盖模式: {}", overwrite);
// 这里添加实际的解压逻辑
extract_file(file, directory.as_ref(), *overwrite)?;
}
}
println!("\n任务执行完成!");
Ok(())
}
/// 模拟文件压缩函数
fn compress_file(input: &PathBuf, output: Option<&PathBuf>, level: u8) -> Result<(), Box<dyn std::error::Error>> {
println!("正在压缩文件: {} (级别: {})", input.display(), level);
// 实际压缩逻辑实现
Ok(())
}
/// 模拟文件解压函数
fn extract_file(file: &PathBuf, directory: Option<&PathBuf>, overwrite: bool) -> Result<(), Box<dyn std::error::Error>> {
println!("正在解压文件: {} (覆盖: {})", file.display(), overwrite);
// 实际解压逻辑实现
Ok(())
}
/// 测试函数
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_parsing() {
// 测试配置解析
let config = Config {
config_file: Some(PathBuf::from("config.toml")),
log_level: "debug".to_string(),
debug: true,
};
assert!(config.config_file.is_some());
assert_eq!(config.log_level, "debug");
assert!(config.debug);
}
}
这个完整示例演示了paw库的主要功能:
- 基本参数解析
- 嵌套子命令
- 数组参数处理
- 默认值设置
- 帮助信息生成
- 错误处理
使用方法:
# 显示帮助信息
cargo run -- --help
# 压缩文件示例
cargo run -- compress -i input.txt -o output.zip -l 9
# 解压文件示例
cargo run -- extract -f archive.zip -d output_dir -o
# 使用文件列表
cargo run -- -f file1.txt -f file2.txt compress -i data.bin