Языков программирования на текущий момент существует превеликое множество. Одни безусловно хороши для определенных целей, другие признаются универсальными и используются многими для решения повседневных задач. В этой статье я хочу рассказать, как и почему Rust стал для меня основным и любимым языком для решения персональных задач самого разнообразного профиля, и что именно доставляет мне особенное удовольствие при его использовании. Хочу сразу заметить, что эта статья целиком и полностью — субъективное мнение автора, единственная цель которой — заинтересовать читателей, ценящих в программировании как хобби те же самые вещи, что и он сам, и речь в ней не пойдёт ни о быстродействии, ни о востребованности языка в сфере IT, ни о каких-либо других технических составляющих этой области, вокруг которой часто возникают разного рода споры. Я остановлюсь на том, что Rust — быстрый и безопасный компилируемый ЯП общего назначения. Об остальном — далее. Лично я в первую очередь делю все ЯП на две большие группы: интерпретируемые и компилируемые. Для личных проектов (разумеется, крупнее скриптов автоматизации) я искал именно второй, так как ключевой для меня была возможность переносить исполняемые файлы на внешних и облачных дисках и запускать их на офисных ПК без каких-либо проблем.
Важным условием при выборе также была возможность без трудностей скомпилировать исполняемые файлы под Windows, Mac OS и дистрибутивы Linux, так как рабочих машин у меня несколько, а запускаться и работать код должен на каждой. Некоторые из проектов шли даже под Raspberry Pi, где мне вдобавок требовалось бережное отношение к памяти. Ну и напоследок я искал простоту в использовании (не в написании кода): чтобы библиотеки ставились (и писались) самым очевидным и удобным образом, чтобы структура проектной директории была простой и понятной, а общение с компилятором – приятным и безболезненным. За ковидный карантин я успел перепробовать множество разных языков, остановившись в итоге на Расте. Давайте узнаем, почему. Так как, пожалуй, большинство читателей ранее с этим языком не взаимодействовали, я начну с самого начала: процесса первого знакомства. В процессе поиска своего идеального ЯП, очень часто я сталкивался с трудностями уже на этом этапе. Где-то были определенные сложности в выборе и настройке IDE, где-то установка или использование компилятора требовало множества разных манипуляций, которые сходу отпугивали и отбивали желание работать. Давайте взглянем, что предстоит пройти человеку, решившему с нуля написать на Расте простейший "Hello World".
Для начала загрузим rustup – программу, которая установит и будет поддерживать в актуальном состоянии все необходимое для написания программ. На Unix-подобных ОС сделать это можно одной командой:  Дополнительные инструкции по установке, а также версия для Windows доступны на официальном сайте. После установки утилиты проверять обновления системы можно командой rustup update. В остальном для работы сама утилита нам больше не понадобится, ведь все остальные манипуляции мы будем проводить с системой сборки и пакетным менеджером системы – cargo. Для начала проверим версию и убедимся, что все встало как надо, выполнив команду cargo --version.
Порядок? Идём дальше.
Сделаем cd в папку, где храним все проекты и попросим cargo создать новый командой cargo new hello-rust.
В папке будет создана новая директория со всеми необходимыми файлами: Cargo.toml здесь – файл манифеста, в котором хранятся все метаданные проекта. Подробнее о нем – чуть позже.
src/main.rs – не трудно догадаться, файл с исходным кодом нашего проекта. Сразу после создания проекта в нем появляется код, выводящий в терминал Hello, world!.
Можно, даже не открывая его, скомандовать cargo run и получить желаемое. Вот и все. Для меня впервые путь к "Hello World" оказался невероятно дружелюбным и простым.
Но, разумеется, выводом текста в консоль никто ограничиваться не будет. Следующий шаг – учиться, учиться, и еще раз учиться. Взглянуть целиком на официальный Quick Start Guide можно здесь Ключевым моментом для любого, решившего выучить новый ЯП, будет, разумеется, сам процесс изучения. Вопрос доступности и качества документации и справочных материалов здесь встаёт особенно остро. Давайте узнаем, как с этим обстоят дела у Раста. Спойлер: обстоят они просто замечательно. Одна лишь официальная документация включает в себя множество самых разнообразных изданий, каждое из которых проработано самым детальным образом. Вот лишь малая часть информации, доступная на официальном сайте: Вместе с самим языком документация постоянно обновляется и дополняется, а вкупе с множеством форумов и вовсе даёт абсолютно исчерпывающую информацию об использовании. Лично у меня путь от первого знакомства до свободного написания сложных программ и библиотек занял месяц. Много это или мало – судите сами. Когда знаний и опыта наконец достаточно, самое время написать что-нибудь интересное. Следующее, за что я собираюсь хвалить Раст —  Нельзя отрицать, что код на Rust не самый читабельный и очевидный для непосвященного пользователя. Нельзя также не заметить, что вместе с пониманием устройства всех деталей синтаксиса приходит и любовь к нему. Во первых – точки с запятой и фигурные скобки. Да, многие на дух такое не переносят, считая пережитком прошлого. Я немного другого мнения: при работе с большими объемами кода, который временами приходится кардинально менять, скобки – спасение, а точки с запятой позволяют мне при особо острой необходимости писать последовательности команд одной строкой. Ставить их везде, кстати, вовсе не обязательно: Во вторых – функции. Выглядят они в Расте так: Лично я – ярый сторонник именно такого вида записи, встречающегося и в других языках. Решение, принятое, например, в C++ или C# (с указанием типа возвращаемого значения вместо ключевого слова fn), на мой взгляд, куда менее очевидно, особенно если приходится иметь дело со сложными типами. Далее вкратце перечислю мои самые любимые сахара: Импорт библиотек реализован здесь максимально кратким и эффективным образом, без лишних ключевых слов и с удобным наследованием: use std::fs импортирует только модуль fs из std, use std::io::{Write, Read} возьмет структуры Write и Read из предыдущего, use std::{io, fs::File, time::*} импортирует модуль io из std, структуру File модуля fs из std и все вложенные в модуль time из std модули и структуры. Одной строкой. В крупных проектах с десятками зависимостей в одном файле такие возможности – просто спасение. Написание кода, который должен выполниться до сборки программы (к примеру установка порядка условной компиляции), реализовано здесь крайне простым образом. Так, например, всего в одну строку можно задать включение определенного модуля лишь в сборку под MacOS: #[cfg(target_os = "macos")]. Идентичный этому синтаксис у всех подобных макросов: #[derive(PartialEq, Eq)], #[post("/user", data = "<new_user>")], #[test] и так далее. Лично мною такое решение воспринимается куда охотнее, чем аналогичные решения в тех же крестах. Match в Расте – продвинутая версия знакомого многим switch/case. Давайте взглянем, на что он способен: Мощная и удобная штука, которую я использую практически в каждом проекте. Принципы обработки ошибок, конечно, имеют весьма посредственное отношение к синтаксису, но затронуть я хочу их максимально поверхностно, чтобы не нагружать читателя лишней информацией, а лишь продемонстрировать базовые принципы этого процесса. Error handling – это очень важно. Когда я пишу проект, что должен как можно дольше оставаться в поднятом состоянии и восстанавливаться от любых возможных ошибок, я хочу быть уверенным, что обработал 100% их всех. В этом мне помогает, на мой взгляд, одна из самых важных особенностей языка, ведь я всегда знаю, в каком месте может возникнуть ошибка. Особенность эта – обработка ошибок, основанная на результате каждой опасной операции, а не на исключениях.
Для этого в языке предусмотрено два основных типа: Option и Result. Для начала – о первом. Вместо массивного решения с match можно использовать символ ?, чтобы выполнять код только в случае, когда необходимое значение есть: Похожее решение реализовано, например, в языке Swift, где вместо Some напрямую передаётся значение, а заменой None служит кейворд nil. Option возвращается функциями, выполнение которых не всегда означает получение результата. А так как Раст не даст мне незаметно взять возвращённый функцией результат, заставив меня либо обработать и Some, и None, либо развернуть результат с помощью unwrap(), что вызовет невосстанавливаемое исключение (панику, подробнее о ней чуть позже), я гарантированно получаю уверенность в отсутствии неожиданных "вылетов" своей программы из-за отсутствия чего-либо, что должно быть, и чего нет. Result работает аналогично, но используется именно для обработки ошибок, возникших во время выполнения кода. В случае, если в успешном выполнении кода или получении искомого результата мы уверены на все сто, Option и Result могут быть развернуты: Панику можно вызвать самостоятельно: Таким образом код получается крайне безопасным, что дает мне лишнюю толику спокойствия. Возвращаясь к обсуждению синтаксиса: вместо while true Rust поддерживает одно ключевое слово loop, что, почему-то, особенно меня умиляет. Замечательно, код написан и мы им довольны. Давайте подробнее посмотрим на cargo, утилиту, которая помогала нам в этом непростом процессе. При работе с Растом вам в принципе не нужна ни IDE, ни даже продвинутый редактор кода. Все необходимые манипуляции с кодом, включая линт чек, сборку, публикацию и загрузку внешних модулей выполняет CLI утилита cargo. Взглянем, как это выглядит на практике. Но как добавить в проект зависимость? Очень просто. В этом нам поможет Cargo.toml – упомянутый ранее файл манифеста, автоматически созданный cargo вместе с нашим проектом.
Ознакомимся с его содержанием: Процесс поиска и добавления модулей реализован здесь необыкновенно просто: Эта всемогущая утилита также обладает невероятно детальным выводом сообщений об ошибках и предупреждений, возникших во время сборки, как при работе из командной строки: так и с помощью множества официальных плагинов для разных редакторов кода:   Вот этим и покорил меня Rust. Невероятным вниманием к деталям, очевидностью процесса сборки и работы с модулями, широкой экосистемой, любопытным синтаксисом и обилием справочных материалов. Он упорядочил работу над моими проектами, поставив ее на поток. В качестве примера хочу поделиться одним из своих открытых проектов — программой, шифрующей файлы с помощью симметричного алгоритма AES по двум ключам. Я написал ее в попытке создать наиболее простое и легкое кроссплатформенное решение для скрытия своих данных от посторонних глаз. Она поддерживает фильтрацию файлов по размерам, типам, именам, индексам и интервалам и работает с вложенными папками. Теперь мои планы на будущее – ещё больше погрузиться в изучение этого языка, познав самые тёмные его уголки.  Если у вас был похожий приятный опыт, но касательно другого ЯП, расскажите мне об этом в комментариях, мне будет жутко интересно почитать.
Спасибо за внимание, надеюсь, сегодня вы узнали для себя что-то новое.  P.S. Основой для этой статьи послужили рассказы и опыт одного моего друга. Облачные серверы от Маклауд отлично подходят за разработки под Rust. Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!