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::Argspaw中包装。

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"

1 回复

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
回到顶部