Skip to content

Ch 28: 程序参数解析

程序参数解析是命令行工具的基础能力。Rust提供了多种方式处理命令行参数,从简单的std::env::args到功能完整的clap crate。

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);
}
}

运行示例:

Terminal window
$ cargo run -- arg1 arg2 "hello world"
程序名: target/debug/myapp
参数个数: 4
参数0: target/debug/myapp
参数1: arg1
参数2: arg2
参数3: hello world
use std::env;
fn main() {
// 处理可能包含非UTF-8字符的参数
for arg in env::args_os() {
println!("{:?}", arg);
}
}

方法签名:

pub fn args() -> Args
pub fn args_os() -> ArgsOs
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
}
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);
}
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!("清理完成");
}
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);
}

对于复杂的命令行工具,推荐使用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);
}
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);
}
}
  1. args[0]是程序名:不是用户输入的参数
  2. 引号处理:shell会解析引号,args已处理完毕
  3. Unicode:args()保证UTF-8,args_os()处理其他编码
  4. 性能:args()每次调用创建新迭代器,避免循环中重复调用
  5. 安全性:用户输入需要验证和清理

程序参数解析的层次:

  • std::env::args() - 基础参数访问
  • std::env::var() - 环境变量
  • 手动解析 - 简单场景
  • clap crate - 复杂场景

根据应用复杂度选择合适的方法:

  • 简单脚本:env::args + 手动解析
  • 工具程序:clap derive模式
  • 复杂CLI:clap builder模式 + 子命令