# Глава 6. Функция main()
Точкой входа (entry point) программы на Rust является функция `main()`. Эта функция не имеет параметров и, как правило, не имеет возвращаемого значения:
```rust {.example_for_playground .example_for_playground_001}
fn main() {
println!("This is the simplest Rust program.");
}
```
Для сравнения небольшая программа _hello_ на языке C:
```c
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf(
"The necessary argument is missing.\n"
"Please run '%s <name>'\n", argv[0]);
return 1;
}
printf("Hello %s!\n", argv[1]);
return 0;
}
```
Программа _hello_ печатает приветствие, используя первый аргумент командной строки в качестве имени. Вызов `./hello human` выведет в консоль `Hello human!`, и при завершении программа вернет 0. Программа, вызванная без аргументов, напечатает сообщение об ошибке с подсказкой и завершится с кодом 1:
```
The necessary argument is missing.
Please run './hello <name>'
```
## Получение аргументов командной строки в Rust
В программе на C аргументы командной строки передаются прямо в `main()`. В Rust аргументы командной строки в программу передаются иначе. Для получения аргументов можно воспользоваться модулем [std::env](https://doc.rust-lang.org/std/env) из стандартной библиотеки:
```rust {.example_for_playground .example_for_playground_002}
use std::env;
fn main() {
let argv: Vec<String> = env::args().collect();
println!("The program path and name: '{}'.", argv[0]);
let argc = argv.len();
println!("The program got {} arguments:", argc - 1);
for i in 1..argc {
println!("{:>4} - {:?}", i, argv[i]);
}
}
```
Функция `env::args()` возвращает итератор по аргументам процесса, а `collect()` преобразует итератор в коллекцию. В данном случае это массив строк, первым элементом которого является имя исполняемого файла. Вызов программы с аргументами `./show_args first 2 "t h i r d"` напечатает:
```
The program path and name: './show_args'.
The program got 3 arguments:
1 - "first"
2 - "2"
3 - "t h i r d"
```
Для более удобной работы с аргументами командной строки есть крейт [clap](https://docs.rs/clap/latest/clap/). О крейтах и их использовании будет рассказано в другой главе.
## Возвращение результата работы программы
Для возврата результатов в модуле [std::result](https://doc.rust-lang.org/std/result/) стандартной библиотеки определен специальный тип:
```rust
enum Result<T, E> {
Ok(T),
Err(E),
}
```
Это перечисление с двумя вариантами `Ok` и `Err`. Типы `T` и `E` являются обобщенными параметрами перечисления `Result<T, E>`. Обобщенные типы и перечисления будут рассмотрены в следующих главах. Сейчас важно запомнить, что в случае успеха внутри варианта `Ok` находится значение типа `T`. При неудаче внутри варианта `Err` находится ошибка типа `E`.
Для функции `main()` в качестве типа `T` логично использовать единичный тип `()`. Для обозначения ошибок можно использовать целый тип, строку, перечисление и другое. В программе _hello_, переписанной с C на Rust, в качестве возвращаемого типа `main()` используется `Result<(), ErrorCode>`. Здесь `ErrorCode` — небольшое перечисление с одним вариантом ошибки: `MissingArgument`.
```rust
#[derive(Debug)]
enum ErrorCode {
MissingArgument
}
fn main() -> Result<(), ErrorCode> {
let argv: Vec<String> = env::args().collect();
if argv.len() < 2 {
println!(
"The necessary argument is missing.\n\
Please run '{} <name>'", argv[0]);
return Err(ErrorCode::MissingArgument);
}
println!("Hello {}!", argv[1]);
Ok(())
}
```
Пояснение к коду:
- Инструкция `#[derive(Debug)]` является атрибутом перечисления `ErrorCode`. А ее часть `derive(Debug)` сообщает компилятору о необходимости автогенерации подходящей реализации типажа `Debug`. Этот типаж отвечает за отображение значений типа при форматировании строки, например в макросе `println!()`.
- Выражение `Err(ErrorCode::MissingArgument)` создает вариант перечисления `Err` с ошибкой `MissingArgument`.
- Выражение `Ok(())` формирует вариант `Ok` с пустым кортежем внутри.
Поведение программы на Rust идентично версии, написанной на C. Немного отличается вывод программы, вызванный без аргументов. Помимо сообщения будет напечатано наименование ошибки:
```
The necessary argument is missing.
Please run './hello <name>'
Error: MissingArgument
```
Имеется альтернативный способ вернуть код из `main()` при завершении программы. В модуле [std::process](https://doc.rust-lang.org/stable/std/process/) реализована функция:
```rust
fn exit(code: i32) -> !
```
Эта функция не возвращает управление вызывающему коду, так как незамедлительно завершает процесс. Код завершения `code` передается в ОС. Следует учитывать, что поскольку эта функция завершает процесс, никакие деструкторы не будут вызваны. Если требуется чистое завершение работы, следует вызывать эту функцию только в той точке, где больше не осталось неосвобожденных ресурсов. Либо вовсе не использовать функцию `exit()`, возвращая из `main()` результат, как показано в примере программы _hello_.
## Заключение
- Точкой входа программы на Rust является функция `main()`.
- Функция `main()` не имеет входных параметров, но может возвращать значение.
- Получить аргументы командной строки можно с помощью модуля `std::env`.
- В качестве возвращаемого значения `main()` следует использовать перечисление `Result<>`.
- В случае успеха `Result<>` будет содержать пустой кортеж `()`.
- Для обозначения ошибки в `Result<>` можно использовать: целое, строку или перечисление.
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!