Ch 28: 程序参数解析
程序参数解析是命令行工具的基础能力。Rust提供了多种方式处理命令行参数,从简单的std::env::args到功能完整的clap crate。
2. std::env::args - 基础参数访问
Section titled “2. std::env::args - 基础参数访问”use std::env;
fn main() { // 获取所有参数 let args: Vec<String> = env::args().collect();
println!("程序名: {}", args[0]); println!("参数个数: {}", args.len());
// 遍历参数 for (i, arg) in env::args().enumerate() { println!("参数{}: {}", i, arg); }}运行示例:
$ cargo run -- arg1 arg2 "hello world"程序名: target/debug/myapp参数个数: 4参数0: target/debug/myapp参数1: arg1参数2: arg2参数3: hello world3. args_os - 处理非UTF-8参数
Section titled “3. args_os - 处理非UTF-8参数”use std::env;
fn main() { // 处理可能包含非UTF-8字符的参数 for arg in env::args_os() { println!("{:?}", arg); }}方法签名:
pub fn args() -> Argspub fn args_os() -> ArgsOs4. std::env::Var - 环境变量访问
Section titled “4. std::env::Var - 环境变量访问”use std::env;
fn main() { // 获取环境变量 match env::var("HOME") { Ok(home) => println!("HOME = {}", home), Err(e) => println!("无法获取HOME: {}", e), }
// 使用is_err检查 if env::var("DEBUG").is_ok() { println!("调试模式已启用"); }}方法签名:
pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError>
pub enum VarError { NotPresent, // 变量不存在 NotUnicode(OsString), // 值不是有效UTF-8}5. 环境变量类型转换
Section titled “5. 环境变量类型转换”use std::env;
fn main() { // 读取并解析为整数 if let Ok(workers) = env::var("WORKERS") { if let Ok(n) = workers.parse::<usize>() { println!("使用 {} 个worker", n); } }
// 使用unwrap_or提供默认值 let port: u16 = env::var("PORT") .unwrap_or("8080".to_string()) .parse() .unwrap_or(8080);
println!("监听端口: {}", port);}6. 简单的参数解析模式
Section titled “6. 简单的参数解析模式”use std::env;
fn main() { let args: Vec<String> = env::args().collect();
if args.len() < 2 { print_usage(); std::process::exit(1); }
match args[1].as_str() { "run" => run_command(&args[2..]), "build" => build_command(&args[2..]), "clean" => clean_command(), "-h" | "--help" => print_usage(), _ => { eprintln!("未知命令: {}", args[1]); print_usage(); std::process::exit(1); } }}
fn print_usage() { println!("用法: myapp <命令>"); println!("命令:"); println!(" run - 运行程序"); println!(" build - 构建程序"); println!(" clean - 清理临时文件");}
fn run_command(args: &[String]) { println!("运行程序,参数: {:?}", args);}
fn build_command(args: &[String]) { println!("构建程序,参数: {:?}", args);}
fn clean_command() { println!("清理完成");}7. 结构化参数解析
Section titled “7. 结构化参数解析”use std::env;
#[derive(Debug)]struct Config { verbose: bool, input_file: String, output_file: Option<String>,}
fn parse_args(args: &[String]) -> Config { let mut verbose = false; let mut input_file = String::new(); let mut output_file = None;
let mut i = 1; while i < args.len() { match args[i].as_str() { "-v" | "--verbose" => verbose = true, "-o" | "--output" => { i += 1; if i < args.len() { output_file = Some(args[i].clone()); } } _ if !input_file.is_empty() => { eprintln!("Unexpected: {}", args[i]); } _ => input_file = args[i].clone(), } i += 1; }
if input_file.is_empty() { eprintln!("错误: 必须指定输入文件"); std::process::exit(1); }
Config { verbose, input_file, output_file }}
fn main() { let args: Vec<String> = env::args().collect(); let config = parse_args(&args);
println!("{:?}", config);}8. clap - 强大的参数解析库
Section titled “8. clap - 强大的参数解析库”对于复杂的命令行工具,推荐使用clap:
// Cargo.toml添加依赖// clap = { version = "4", features = ["derive"] }
use clap::Parser;
#[derive(Parser, Debug)]#[command(name = "myapp")]#[command(about = "一个示例程序")]struct Args { /// 启用的调试模式 #[arg(short, long)] verbose: bool,
/// 输入文件 #[arg(short, long)] input: String,
/// 输出文件(可选) #[arg(short, long)] output: Option<String>,
/// 工作线程数 #[arg(short, long, default_value_t = 4)] workers: usize,}
fn main() { let args = Args::parse(); println!("{:?}", args);}9. 环境变量与参数优先级
Section titled “9. 环境变量与参数优先级”use std::env;
fn main() { // 环境变量优先级较低 let config_path = env::var("CONFIG_PATH") .unwrap_or_else(|_| ".config.json".to_string());
// 命令行参数优先级较高 let args: Vec<String> = env::args().collect();
if args.len() > 1 { println!("使用命令行指定的配置: {}", args[1]); } else { println!("使用环境变量配置: {}", config_path); }}10. 注意事项
Section titled “10. 注意事项”- args[0]是程序名:不是用户输入的参数
- 引号处理:shell会解析引号,args已处理完毕
- Unicode:args()保证UTF-8,args_os()处理其他编码
- 性能:args()每次调用创建新迭代器,避免循环中重复调用
- 安全性:用户输入需要验证和清理
11. 总结
Section titled “11. 总结”程序参数解析的层次:
std::env::args()- 基础参数访问std::env::var()- 环境变量- 手动解析 - 简单场景
- clap crate - 复杂场景
根据应用复杂度选择合适的方法:
- 简单脚本:env::args + 手动解析
- 工具程序:clap derive模式
- 复杂CLI:clap builder模式 + 子命令