Прием аргументов командной строки

RustRustBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Добро пожаловать в Прием аргументов командной строки. Эта лабораторная работа является частью Rust Book. Вы можете практиковать свои навыки Rust в LabEx.

В этой лабораторной работе мы создадим новый проект под названием "minigrep", который принимает два аргумента командной строки: строку для поиска и путь к файлу.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-100418{{"Прием аргументов командной строки"}} rust/function_syntax -.-> lab-100418{{"Прием аргументов командной строки"}} rust/expressions_statements -.-> lab-100418{{"Прием аргументов командной строки"}} rust/method_syntax -.-> lab-100418{{"Прием аргументов командной строки"}} rust/operator_overloading -.-> lab-100418{{"Прием аргументов командной строки"}} end

Прием аргументов командной строки

Создадим новый проект, как всегда, с помощью cargo new. Назовем наш проект minigrep, чтобы отличить его от утилиты grep, которая может уже быть установлена на вашей системе.

$ cargo new minigrep
     Created binary (application) `minigrep` project
$ cd minigrep

Первое задание - заставить minigrep принимать два аргумента командной строки: путь к файлу и строку для поиска. То есть, мы хотим, чтобы наша программа могла запускаться с помощью cargo run, двумя дефисами, чтобы указать, что следующие аргументы предназначены для нашей программы, а не для cargo, строкой для поиска и путем к файлу, в котором нужно искать, вот так:

cargo run -- searchstring example-filename.txt

В настоящее время программа, сгенерированная с помощью cargo new, не может обрабатывать аргументы, которые мы ей передаем. Некоторые существующие библиотеки на https://crates.io могут помочь при написании программы, которая принимает аргументы командной строки, но поскольку вы только учите этот концепт, давайте реализуем эту возможность сами.

Чтение значений аргументов

Чтобы 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, позволяя программам использовать имя, по которому они были вызваны при выполнении. Часто удобно иметь доступ к имени программы, если вы хотите вывести его в сообщениях или изменить поведение программы в зависимости от того, какой командный алиас был использован для вызова программы. Но для целей этой главы мы будем игнорировать его и сохранять только два нужных нам аргумента.

Сохранение значений аргументов в переменные

Программа в настоящее время может получать доступ к значениям, указанным в качестве аргументов командной строки. Теперь нам нужно сохранить значения двух аргументов в переменные, чтобы использовать их в остальной части программы. Мы это делаем в листинге 12-2.

Имя файла: src/main.rs

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    let query = &args[1];
    let file_path = &args[2];

    println!("Searching for {}", query);
    println!("In file {}", file_path);
}

Листинг 12-2: Создание переменных для хранения аргумента запроса и аргумента пути к файлу

Как мы видели, когда выводили вектор, имя программы занимает первое значение в векторе по индексу args[0], поэтому мы начинаем считывать аргументы с индекса 1. Первым аргументом, который принимает minigrep, является строка, которую мы ищем, поэтому мы помещаем ссылку на первый аргумент в переменную query. Второй аргумент будет путем к файлу, поэтому мы помещаем ссылку на второй аргумент в переменную file_path.

Мы временно выводим значения этих переменных, чтобы убедиться, что код работает, как мы ожидаем. Запустим эту программу снова с аргументами test и sample.txt:

$ cargo run -- test sample.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt

Отлично, программа работает! Значения нужных нам аргументов сохраняются в правильные переменные. Позже мы добавим обработку ошибок, чтобы обработать некоторые возможные ошибочные ситуации, например, когда пользователь не указывает аргументы; на данный момент мы будем игнорировать эту ситуацию и сосредоточиться на добавлении возможностей чтения файлов.

Резюме

Поздравляем! Вы завершили лабораторную работу по Приему аргументов командной строки. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.