Чтение значений аргументов
Чтобы minigrep
мог читать значения аргументов командной строки, которые мы передаем ему, нам понадобится функция std::env::args
, предоставленная в стандартной библиотеке Rust. Эта функция возвращает итератор по аргументам командной строки, переданным в minigrep
. Мы подробно рассмотрим итераторы в главе 13. На данный момент вам нужно знать только два важных момента о итераторах: итераторы генерируют серию значений, и мы можем вызвать метод collect
для итератора, чтобы превратить его в коллекцию, например, вектор, который содержит все элементы, генерируемые итератором.
Код в листинге 12-1 позволяет программе minigrep
читать любые аргументы командной строки, переданные ей, и затем собирать их значения в вектор.
Имя файла: src/main.rs
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
dbg!(args);
}
Листинг 12-1: Сбор аргументов командной строки в вектор и их вывод
Сначала мы подключаем модуль std::env
с помощью инструкции use
, чтобы иметь возможность использовать его функцию args
. Обратите внимание, что функция std::env::args
находится на двух уровнях вложенности в модулях. Как мы обсуждали в главе 7, в случаях, когда нужная функция находится на нескольких уровнях вложенности, мы предпочитаем подключать родительский модуль, а не функцию. Таким образом, мы можем легко использовать другие функции из std::env
. Это также менееambigующе, чем добавление use std::env::args
и затем вызов функции только с args
, потому что args
может быть легко mistaken за функцию, определенную в текущем модуле.
Функция args и недопустимый Unicode
Обратите внимание, что std::env::args
будет вызывать панику, если какой-либо аргумент содержит недопустимый Unicode. Если ваша программа должна принимать аргументы, содержащие недопустимый Unicode, используйте std::env::args_os
вместо этого. Эта функция возвращает итератор, который генерирует значения OsString
вместо String
. Мы выбрали использовать std::env::args
здесь для простоты, потому что значения OsString
отличаются в зависимости от платформы и сложнее обрабатывать, чем значения String
.
В первой строке функции main
мы вызываем env::args
, и сразу же используем collect
, чтобы превратить итератор в вектор, содержащий все значения, генерируемые итератором. Мы можем использовать функцию collect
для создания различных типов коллекций, поэтому мы явно указываем тип args
, чтобы указать, что мы хотим получить вектор строк. Хотя вы очень редко будете нужно указывать типы в Rust, функция collect
- это одна из тех функций, для которых вы часто должны указывать тип, потому что Rust не может определить тип коллекции, которую вы хотите получить.
Наконец, мы выводим вектор с помощью макроса отладки. Попробуем запустить код сначала без аргументов, а затем с двумя аргументами:
$ cargo run
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
]
$ cargo run -- needle haystack
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
"needle",
"haystack",
]
Обратите внимание, что первое значение в векторе - это "target/debug/minigrep"
, которое является именем нашего бинарника. Это соответствует поведению списка аргументов в C, позволяя программам использовать имя, по которому они были вызваны при выполнении. Часто удобно иметь доступ к имени программы, если вы хотите вывести его в сообщениях или изменить поведение программы в зависимости от того, какой командный алиас был использован для вызова программы. Но для целей этой главы мы будем игнорировать его и сохранять только два нужных нам аргумента.