Как получить аргументы командной строки в Rust?
Получение аргументов командной строки через std::env::args()
В Rust для доступа к аргументам командной строки используется функция std::env::args(). Она возвращает итератор Args, который не реализует трейт Display (поэтому println!("{:?}", args) выводит сырое представление), но его можно преобразовать в коллекцию строк.
Базовое решение (без внешних крейтов)
Самый простой способ — собрать аргументы в Vec<String> и работать с ними:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
// Проверяем количество аргументов (первый — имя программы)
if args.len() < 3 {
eprintln!("Ошибка: недостаточно аргументов");
eprintln!("Использование: {} <файл> <режим>", args[0]);
std::process::exit(1);
}
let filename = &args[1];
let mode = &args[2];
match mode.as_str() {
"read" => {
println!("Читаем файл: {}", filename);
// Здесь будет логика чтения
}
"write" => {
println!("Записываем в файл: {}", filename);
// Здесь будет логика записи
}
_ => {
eprintln!("Ошибка: неизвестный режим '{}'. Используйте 'read' или 'write'", mode);
std::process::exit(1);
}
}
}
Использование итератора напрямую
Если не хотите собирать все аргументы в вектор, можно работать с итератором через skip() и next():
use std::env;
fn main() {
let mut args = env::args().skip(1); // Пропускаем имя программы
let filename = match args.next() {
Some(arg) => arg,
None => {
eprintln!("Ошибка: не указано имя файла");
std::process::exit(1);
}
};
let mode = match args.next() {
Some(arg) => arg,
None => {
eprintln!("Ошибка: не указан режим (read/write)");
std::process::exit(1);
}
};
println!("Файл: {}, Режим: {}", filename, mode);
}
Продвинутый подход с крейтом clap
Для серьёзных проектов рекомендую крейт clap — он даёт автогенерацию справки, парсинг флагов и проверку типов:
// Добавьте в Cargo.toml: clap = { version = "4.0", features = ["derive"] }
use clap::Parser;
#[derive(Parser)]
#[command(name = "myapp")]
#[command(about = "Утилита для чтения/записи файлов")]
struct Cli {
/// Имя файла для обработки
filename: String,
/// Режим работы: read или write
#[arg(value_parser = clap::builder::PossibleValuesParser::new(["read", "write"]))]
mode: String,
}
fn main() {
let cli = Cli::parse();
match cli.mode.as_str() {
"read" => println!("Читаем {}", cli.filename),
"write" => println!("Записываем {}", cli.filename),
_ => unreachable!(), // clap уже проверил значения
}
}
Крейт clap автоматически сгенерирует справку при запуске с --help и сообщение об ошибке при неверных аргументах.
Важные моменты
- Первый аргумент (индекс 0) — всегда путь к исполняемому файлу. Пропускайте его через
skip(1), если он не нужен. - Обработка ошибок: всегда проверяйте количество аргументов и выводите понятное сообщение, иначе пользователь получит панику с непонятным текстом.
- Кодировка:
std::env::args()возвращает строки в кодировке ОС. Для работы с некорректным Unicode используйтеstd::env::args_os(), который возвращаетOsString. - Производительность:
collect()в вектор — это O(n) по времени и памяти. Для простых скриптов это нормально, но если аргументов миллионы, лучше использовать итератор.
Альтернативный подход: ручной парсинг с помощью std::env::args_os()
Если вам нужно работать с аргументами, которые могут содержать невалидный Unicode (например, пути с нестандартными символами в Windows), используйте std::env::args_os(). Она возвращает OsString, который можно преобразовать в строку через to_str():
use std::env;
use std::ffi::OsString;
fn main() {
let args: Vec<OsString> = env::args_os().collect();
if args.len() < 3 {
eprintln!("Ошибка: недостаточно аргументов");
return;
}
// Преобразуем только если уверены в корректности Unicode
let filename = args[1].to_str().expect("Имя файла должно быть валидным Unicode");
let mode = args[2].to_str().expect("Режим должен быть валидным Unicode");
println!("Файл: {}, Режим: {}", filename, mode);
}
Когда это полезно?
- При работе с файловыми системами в Windows (где пути могут содержать не-UTF8 символы).
- Если программа должна корректно обрабатывать аргументы, переданные из скриптов с разными кодировками.
- Для максимальной совместимости с системными вызовами.
Обратите внимание: to_str() может вернуть None, если строка не является валидным UTF-8. В реальном коде стоит обрабатывать эту ситуацию через match или unwrap_or_else.
Для большинства простых утилит достаточно std::env::args(), но знание args_os() пригодится для более сложных сценариев.