Что пишут на rust

от admin

Введение в программирование на Rust

Rust — это перспективный язык программирования, набирающий рекордную популярность для низкоуровневых систем, таких как операционные системы и компиляторы.

В 2020 году по итогам опроса разработчиков Stack Overflow самым любимым языком программирования уже пятый год подряд был признан Rust. Многие разработчики уверены в том, что Rust скоро обгонит C и C++ благодаря своему средству проверки заимствований и решению давних проблем, таких как управление памятью, а также неявная и явная типизация.

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

Вот что мы рассмотрим в статье.

  • Что такое Rust?
  • «Hello World!» на Rust.
  • Основы синтаксиса Rust.
  • Промежуточный Rust: владение и структуры.
  • Система сборки Rust: Cargo.
  • Продвинутые концепции для дальнейшего изучения.

Что такое Rust?

Rust — это мультипарадигмальный статически типизированный язык программирования с открытым исходным кодом, используемый для создания операционных систем, компиляторов и других программно-аппаратных средств. Он был разработан Грейдоном Хором в Mozilla Research в 2010 году.

Rust оптимален с точки зрения производительности и безопасности, причем акцент здесь сделан на безопасном параллелизме. Этот язык больше всего похож на C или C++, но использует средство проверки заимствований для подтверждения безопасности ссылок.

Rust — это идеальный язык системного программирования для разработки встроенного программного обеспечения для платформ без операционной системы. Наиболее распространено применение Rust в низкоуровневых системах, например ядрах операционных систем или в микроконтроллерах.

Rust отличается от других низкоуровневых языков отличной поддержкой параллельного программирования с предотвращением гонки данных.

Зачем изучать Rust?

Язык программирования Rust идеально подходит для низкоуровневого системного программирования из-за системы выделения памяти с уникальной концепцией владения и приверженности оптимальному и безопасному параллелизму. И хотя его все еще нечасто используют в крупных компаниях, Rust остается одним из языков, получающих самые высокие оценки.

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

«Hello World!» на Rust

Лучший способ освоить Rust — реальная практика. Для начала напишем первую программу hello-world .

Разберем все части этого кода.

fn

fn — это сокращение от function («Функция»). В Rust (как и в большинстве других языков программирования) функция как бы говорит: «Сообщите мне информацию, а я сделаю то-то и то-то и затем дам ответ».

main

Функция main — это то место, где начинается программа.

Скобки содержат список параметров для этой функции. Сейчас он пуст, то есть параметров нет. Но скоро мы увидим много функций с параметрами.

Фигурные скобки. Ими обозначается начало и конец тела кода. Тело сообщает, что делает функция main .

println!

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

("Hello, world!")

А это список параметров для вызова макроса. Мы как бы говорим: «Вызовите макрос println с этими параметрами». Макрос println такой же, как функция main , только у него параметр вместо списка параметров. Позже мы еще увидим функции и параметры.

"Hello, world!"

Дальше идет строка. Строки состоят из нескольких собранных вместе букв или символов. Для обозначения строки эти символы помещаются в кавычки ( " ). Затем строки передаются для макросов типа println! и других функций, с которыми мы еще поиграем.

А это точка с запятой. Она обозначает конец одной инструкции, как точка в предложении. Инструкции — это указания компьютеру выполнить конкретное действие. Чаще всего инструкция состоит из всего одной строки кода. В нашем случае она вызывает макрос. Есть и другие виды инструкций, которые мы скоро увидим.

Основы синтаксиса Rust

Теперь рассмотрим основные части программы на Rust и способы их реализации.

Переменные и их изменяемость

Переменные — это точки данных, которые сохраняются и помечаются для последующего использования. Формат объявлений переменных таков:

Имя переменной должно быть информативным, т. е. описывать, чем является ее значение. Например:

Здесь создана переменная my_name со значением "Ryan" .

Совет�� Всегда давайте переменным названия, начинающиеся со строчной буквы, а новое слово начинайте с заглавной.

В Rust переменные неизменяемы по умолчанию, т. е. их значение нельзя изменить после того, как они заданы.

Например, вот этот код выдаст ошибку во время компиляции:

Ошибка в строке 4, где мы попытались установить значение x = 6 . Но значение x уже задано в строке 2 и изменить его нельзя.

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

Представьте, что у вас есть две функции: functionA , которая использует переменную, имеющую значение 10 , и функция functionB , которая изменяет эту же переменную. Выполнение функции functionA будет прервано!

Чем больше у вас становится переменных и функций, тем легче случайно изменить их значения. Такого рода ошибки поддаются отладке с трудом, поэтому в Rust предпочитают избегать их в принципе.

Чтобы переопределить это значение по умолчанию и создать изменяемую переменную, объявим ее вот так:

Изменяемые переменные чаще всего используются как переменные-итераторы или как переменные в структурах цикла while .

Типы данных

Пока что мы видели, что значения переменных задаются либо с помощью фраз (называемых строками), либо целых чисел. Эти переменные представляют собой различные типы данных, которые обозначают, какой вид имеют содержащиеся в них значения и какие операции они выполняют.

В Rust имеется такая функциональная особенность, как определение типа. Она позволяет компилятору предположить, какой тип данных должен быть у той или иной переменной, даже в отсутствие четкого указания. Так экономится время при написании объявлений переменных с очевидными типами, например для строки my_name .

Указав между именем переменной и ее значением : &[type] , мы явно определим тип для этой переменной.

В этом случае наш пример с объявлением my_name будет переписан следующим образом:

Явная типизация позволяет соответствующим образом определять тип переменной и избегать ошибок в тех случаях, когда тип переменной неочевиден. Rust сделает наиболее правильное с его точки зрения предположение, но это может привести к неожиданному поведению.

Допустим, имеется переменная answer , которая записывает ответ пользователя в форму.

Rust неявно определит строковый тип для этой переменной, так как она приводится в кавычках. Тогда как переменная наверняка булева, что подразумевает выбор между двумя вариантами: true и false .

Во избежание недопонимания со стороны других разработчиков и для недопущения синтаксической ошибки поменяем объявление следующим образом:

Основные типы на Rust:

  • Integer: целочисленный (целые числа).
  • Float: числа с плавающей запятой (с десятичными знаками).
  • Boolean: логический (булев) с выбором между двумя вариантами ( true или false ).
  • String: строковый (набор символов, заключенных в кавычки).
  • Char: скалярное значение Юникод, представляющее конкретный символ.
  • Never: тип без значения (обозначается как ! ).

Функции

Функции — это наборы связанного кода на Rust, объединенные под кратким условным обозначением и вызываемые из других частей программы.

Пока что мы использовали только базовую функцию main() . Rust также позволяет создавать дополнительные, собственные функции, и это очень важная для большинства программ возможность. Функции часто представляют собой одну повторяющуюся задачу, например addUser (добавление пользователя) или changeUsername (изменение имени пользователя). Эти функции затем повторно используются всякий раз, когда требуется выполнить то же самое поведение.

Функции, отличные от main , должны иметь уникальное имя и возвращать результат. Кроме того, они передают параметры (один или несколько), которые представляют собой входные данные для использования внутри функции.

Вот формат для объявления функции:

fn

Это уже знакомое нам сокращение от function («Функция»). За ним в коде Rust следует объявление функции.

[functionName]

Здесь находится идентификатор функции, который будет использоваться при ее вызове.

Эти скобки заполняются любыми параметрами, которые нужны функции. В данном случае никаких параметров не передается, поэтому скобки оставлены пустыми.

[parameterIdentifier]

А здесь передаваемому значению присваивается имя. Это имя выступает в роли имени переменной, ссылающейся на параметр в любом месте тела функции.

[parameterType]

После параметра необходимо явно указать тип. Во избежание путаницы неявная типизация параметров в Rust запрещена.

Фигурные скобки обозначают начало и конец блока кода. Код внутри скобок выполняется при каждом вызове идентификатора функции.

[functionBody]

А это заполнитель для кода функции. Лучше не включать сюда никакого кода, не связанного прямо с выполнением задачи функции.

Добавим немного кода. Переделаем hello-world в функцию say_hello() :

Совет�� Увидели () — значит, вы имеете дело с вызовом функции. Если параметров нет, получаем внутри скобок пустое поле параметров. Сами скобки все равно остаются, указывая на то, что это функция.

Функция создана, теперь вызовем ее из других частей программы. Программа начинается в main() , поэтому вызовем say_hello() оттуда.

Вот как будет выглядеть полная программа:

Комментарии

Комментарии — это сообщения, которые содержат описание того, для чего нужен тот или иной сегмент кода. Они помогают автору кода быстро вспомнить логику дальнейших своих действий, а другим программистам — быстро понять, как устроена программа. Так что написание хороших комментариев полезно всем.

В Rust есть два способа писать комментарии. Первый — использовать двойную косую черту // . В этом случае все, вплоть до конца строки, игнорируется компилятором. Например:

Второй способ — предварять комментарий косой чертой со звездочкой /* и завершать его звездочкой с косой чертой */ . Преимущества такого способа оформления комментариев: 1) есть возможность помещать комментарии в середину строки кода и 2) так легче писать многострочные комментарии. Недостаток в том, что во многих случаях приходится задействовать больше символов, чем просто // .

Совет�� используйте комментарии для «закомментирования» разделов кода, выполнение которых не требуется, но которые позже понадобится добавить.

Условные инструкции

Условные инструкции — это способ создания поведения, которое имеет место только в случае истинности некоего набора условий. С помощью этих инструкций получаются адаптируемые функции, которые отлично справляются с различными программными ситуациями без использования второй функции.

Все условные инструкции содержат проверяемую переменную и целевое значение, а оператор условия ( == , < или > ) определяет их соотношение. В зависимости от состояния переменной применительно к целевому значению возвращается одно из двух логических выражений: true («истинно»), если переменная удовлетворяет целевому значению, и false («ложно»), если нет.

Допустим, нужно сделать функцию для создания учетной записи для любого пользователя, у которого еще нет учетной записи для авторизации в системе.

Это пример условного оператора if . Фактически происходит вот что: если hasAccount соответствует false , учетная запись будет создана. И пользователь будет в ней авторизован независимо от того, уже имелась у него учетная запись или нет.

Вот как выглядит формат оператора if :

Есть три основных условных оператора: if , if else и while .

  • if : если условие истинно, происходит выполнение. В противном случае пропускаем и идем дальше.
  • if else : если условие истинно, выполняется тело кода A. В противном случае выполняется тело кода B.
  • while : тело кода многократно выполняется, пока условие true («истинно»). Как только условие становится false («ложным»), мы идем дальше.

Совет�� необходимо, чтобы в циклах while проверяемая переменная была изменяемой. Если переменная никогда не меняется, такой цикл будет продолжаться бесконечно.

Промежуточный Rust: владение и структуры

Владение

Владение — это центральная особенность Rust и одна из причин такой его популярности.

Во всех языках программирования должна предусматриваться система освобождения неиспользуемой памяти. В некоторых языках, таких как Java, JavaScript или Python, есть сборщики мусора, которые автоматически удаляют неиспользуемые ссылки. В низкоуровневых языках типа C или C++ от разработчиков требуется всякий раз, когда это необходимо, выделять и освобождать память вручную.

Ручное выделение памяти сопряжено с многочисленными проблемами, поэтому практиковать его затруднительно. Когда память выделяется на очень продолжительное время, она расходуется впустую. А слишком раннее освобождение памяти, как и выделение одной и той же памяти дважды, приводит к ошибке.

Rust выгодно отличает от всех этих языков система владения, которая управляет памятью с помощью набора правил, применяемых компилятором во время компиляции.

Вот эти правила владения.

  • У каждого значения в Rust есть переменная, которая называется его владельцем.
  • В каждый конкретный момент времени у значения есть только один владелец.
  • Когда владелец выходит из области видимости, значение удаляется.

А теперь посмотрим, как владение уживается с функциями. Для объявленных переменных память выделяется, пока они используются. Если эти переменные передаются в качестве параметров в другую функцию, выделение перемещается или копируется к другому владельцу и используется у него.

Главный вывод касается разного использования s и x . Сначала x владеет значением 5 , но после выхода ее из области видимости функции main() переменная x должна передать владение параметру number . Ее использование в качестве параметра позволяет продолжить область видимости выделения памяти под значение 5 за пределы исходной функции.

С другой стороны, переменная s не используется в качестве параметра и поэтому память для нее остается выделенной только тогда, когда программа находится внутри function() . По завершении function() значение s никогда больше не потребуется и для высвобождения памяти от него избавляются.

Структуры

Еще одним важным понятием в Rust являются структуры, называемые struct . Это пользовательские типы данных, создаваемые для представления типов объектов. При создании определяется набор полей, для которых все структуры этого типа должны иметь какие-то значения.

Аналогом этих структур в таких языках, как Java и Python, являются классы.

Вот синтаксис объявления структуры:

  • struct сообщает Rust, что следующее объявление определит тип данных struct.
  • [identifier] — это имя типа данных, используемого при передаче параметров, таких как string или i32 , в строковые и целочисленные типы соответственно.
  • <> эти фигурные скобки обозначают начало и конец переменных, необходимых для структуры.
  • [fieldName] — это место, где вы называете первую переменную, которую должны иметь все экземпляры этой структуры. Переменные внутри структуры называются полями.
  • [fieldType] — это место, где во избежание путаницы явно определяется тип данных переменной.

Например, создадим структуру struct Car , которая включает в себя переменную строкового типа brand и переменную целочисленного типа year .

Каждый создаваемый экземпляр типа Car должен иметь значения для этих полей. Поэтому создадим экземпляр Car для конкретного автомобиля со значениями для brand (модели) и year (года выпуска).

Точно так же, как при определении переменных с примитивными типами, определяем переменную Car с идентификатором, на который будем ссылаться позже.

Оттуда будем использовать значения этих полей с синтаксисом [variableIdentifier].[field] . Rust интерпретирует эту инструкцию как «каково значение [поля] для идентификатора [переменной]?».

Вот как выглядит вся структура целиком:

В целом структуры отлично подходят для хранения вместе всей информации, относящейся к тому или иному типу объекта, для реализации и обращения к ней в программе.

Система сборки Rust: Cargo

Cargo — это система сборки и диспетчер пакетов Rust. Это важный инструмент для организации проектов на Rust. Здесь приводится перечень библиотек, необходимых проекту (они называются зависимостями). Он автоматически загружает любые отсутствующие зависимости и собирает программы на Rust из исходного кода.

Программы, с которыми мы имели дело до сих пор, достаточно просты, и поэтому зависимости для них не нужны. А вот при создании более сложных программ вам понадобится Cargo с возможностями инструментов, недоступных в рамках стандартной библиотеки. Cargo также используется для загрузки проектов в портфолио на GitHub, так как они хранят все части и зависимости вместе.

Если скачать Rust с официального сайта, Cargo автоматически устанавливается вместе с компилятором ( rustc ) и генератором документации ( rustdoc ) как часть набора инструментальных средств Rust. Убедиться, что Cargo установлен, помогает ввод в командной строке следующей команды:

Для создания проекта с Cargo запустите в интерфейсе командной строки операционной системы следующее:

Первой командой создается новый каталог hello_cargo . А второй командой этот новый каталог выбирается.

Генерируется манифест под названием Cargo.toml , который содержит все метаданные, необходимые Cargo для компиляции пакета, а также файл main.rs , отвечающий за компиляцию проекта.

Чтобы все это увидеть, наберите:

Перейдите к местоположению вашего каталога и откройте файл Cargo.toml . Внутри вы найдете информацию о проекте. Выглядит это следующим образом:

Все зависимости приведены в категории dependencies .

После завершения проекта введите команду $ cargo run : проект будет скомпилирован и запущен.

Продвинутые концепции для дальнейшего изучения

Несмотря на то, что многие из этих компонентов кажутся маленькими, с каждым из них можно шаг приблизиться к полному освоению Rust! Год от года Rust становится все более популярным, а это значит, что сейчас самое время обзавестись навыками для создания низкоуровневых систем будущего.

Rust с открытым исходным кодом: 24 потрясающих фреймворка, проектов и библиотек

У Rust очень живая и быстро развивающаяся экосистема с открытым исходным кодом, в которой множество участников работают над массой потрясающих проектов.

И если вы спрашиваете — что я могу построить в Rust? Ответ почти на все.

В этой статье будут представлены некоторые библиотеки, фреймворки и репозитории Rust с открытым исходным кодом, которые могут быть полезны для изучения или использования в вашем собственном проекте.

Для вашего удобства я разделил их на такие области, как веб-разработка, разработка игр, блокчейн и другие. Давайте копаться!

Фреймворки веб-разработки для Rust

Можете ли вы создать веб-приложение на Rust? Определенно!

Rust имеет несколько чрезвычайно быстрых веб-фреймворков — Rocket, Actix Web и Yew — и вы можете использовать ту, которая соответствует вашим потребностям и предпочтениям.

Rocket

Rocket — самый доступный веб-фреймворк в экосистеме Rust для новичков. Он легко настраивается и помогает быстро запустить новое приложение. В то же время он позволяет избежать множества ненужных шаблонов. Rocket также имеет множество включенных функций, а это означает, что вам не нужно уходить далеко от фреймворка, чтобы создать все, что вам нужно.

В отличие от Actix Web, фреймворк работает на ночном Rust — «экспериментальной» версии языка.

Actix Web

Actix Web обычно считается более производительным и стабильным, чем Rocket. Внизу он работает с моделью актера, используемой в Erlang и Akka.

В отличие от Rocket, в нем меньше «батарей в комплекте», а это означает, что вам, скорее всего, придется использовать сторонние библиотеки для дополнительной функциональности.

Yew — это фреймворк Rust для создания веб-приложений с помощью WebAssembly. Среди его основных преимуществ он перечисляет компонентную структуру, такую как React и Elm, выдающуюся производительность благодаря поддержке многопоточности и совместимость с JavaScript.

На данный момент он не готов к производству, но должен быть отличным выбором для сторонних проектов и внутреннего инструментария, особенно если вы хотите работать с WASM.

Если вам нужно что-то быстрое и простое для обслуживания статического веб-сайта, Zola — фантастический инструмент для создания быстрых и масштабируемых веб-страниц без каких-либо других зависимостей или раздувания JS.

Деформация

Warp — это фреймворк для веб-серверов, написанный на Rust. По сравнению с Rocket и Actix, он довольно тонкий для веб-фреймворка и предоставит вам только базовую функциональность из коробки.

Разработка игр

Разработка игры на Rust

Rust уникален для разработки игр по той же причине, что и C++: он предсказуемо высокопроизводителен. Вот некоторые из движков, которые вы можете использовать для создания собственной игры на Rust.

Два основных игровых движка Rust — это Bevy и Amethyst. Среди них Беви новее и круче. Это простой движок, управляемый данными, и по сути его можно назвать Amethyst 2.0, поскольку он во многом вдохновлен им.

Чтобы узнать больше о Беви, вы можете почитать книгу Беви.

Аметист

Аметист является более зрелым из двух, и поэтому он имеет больше функций, которые могут вам понадобиться для крупномасштабного проекта, и лучшую интеграцию со сторонними библиотеками. Но Беви быстро догоняет. Если вы ищете движок для своего нового проекта, я бы порекомендовал изучить их оба и посмотреть, какой из них вам больше нравится.

Если вы ищете что-то простое для начала, ggez — это легкая кроссплатформенная игровая платформа для создания 2D-игр с минимальным трением.

Если вы хотите узнать больше о разработке игр на Rust, ознакомьтесь с разделом «Мы уже играем?»

Операционные системы

Операционные системы Rust

Rust — отличная альтернатива C при разработке операционных систем, поскольку он предлагает тот же уровень производительности, заботясь о безопасности памяти. Собственно, разработчики изучают возможность добавления Rust в ядро Linux, и Microsoft тоже экспериментирует с этим.

Вот несколько операционных систем с открытым исходным кодом, написанных исключительно на Rust:

Редокс

Redox — это операционная система, написанная на Rust, которая использует инновации Rust для создания современного микроядра.

intermezzOS

intermezzOS — это обучающая операционная система, специально ориентированная на знакомство с концепциями системного программирования опытных разработчиков из других областей программирования.

Тесей

Тесей — это новая ОС, написанная на Rust, которая представляет новую структуру ОС и утверждает, что предотвращает явление разлива состояния, которое происходит, когда состояние одного объекта постоянно изменяется в результате взаимодействия с другим.

Здесь есть о чем почитать — вот статья по проекту.

Разработка графического интерфейса

Разработка графического интерфейса на Rust

Хотя Rust не слишком известен своей способностью создавать увлекательные пользовательские интерфейсы, все же существует множество хороших библиотек для создания графических интерфейсов.

Друид

Druid — это экспериментальный набор инструментов пользовательского интерфейса для Rust, ориентированный на создание простого и безупречного пользовательского интерфейса. Он ориентирован на данные и вдохновлен современными фреймворками, такими как Flutter, SwiftUI и другими.

Чтобы узнать больше об этом, вы можете почитать книгу Друидов.

Замороженный

Iced — это кроссплатформенная библиотека графического интерфейса, ориентированная на простоту и безопасность типов. Он во многом вдохновлен Вязом. Хотя сейчас это все еще экспериментально, это отличный вариант для создания графического интерфейса прямо в Rust для вашего стороннего проекта.

Набор инструментов для орбитальных виджетов

Orbital Widget Toolkit — это кроссплатформенный набор инструментов для создания масштабируемых пользовательских интерфейсов с помощью Rust. Он ориентирован на скорость, простоту использования и кроссплатформенную совместимость.

Тельца

Tauri — это фреймворк для создания настольных приложений для Windows, Linux и macOS. С его помощью вы можете использовать любую интерфейсную платформу, которая компилируется в HTML / CSS / JS для создания пользовательского интерфейса, и Rust в качестве бэкэнда.

Если вы хотите узнать больше о возможностях разработки графического интерфейса в Rust, вот большой пост, посвященный большинству библиотек.

Блокчейн

Блокчейн Rust

OpenEthereum

Основная цель OpenEthereum — быть самым быстрым, легким и безопасным клиентом Ethereum. Он разработан на Rust и утверждает, что предоставляет базовую инфраструктуру, которая необходима для быстрых и надежных сервисов.

Lighthouse — это клиент Ethereum 2.0 с открытым исходным кодом, написанный на Rust и поддерживаемый Sigma Prime.

Parity Technologies: Polkadot и Substrate

Parity Technologies работает над созданием блокчейн-инфраструктуры для децентрализованной сети.

Среди его проектов — Substrate, модульная структура для разработки блокчейнов, и Polkadot, сеть блокчейнов. Оба этих проекта активно используют Rust в своих реализациях.

Другие проекты

Другие проекты Rust

Вот некоторые из проектов, которые не попадают ни в одну из категорий. Надеюсь, вы найдете что-то классное в этой коллекции «вещей». 🙂

Сервопривод

Servo — это прототип веб-движка, написанный на Rust. Это результат работы Mozilla над созданием нового движка браузера с открытым исходным кодом. В 2020 году Servo перешла от Mozilla к Linux Foundation.

Предполагается, что Servo более безопасен, чем браузеры, написанные на C++, из-за гарантий безопасности памяти Rust, которые уменьшают количество уязвимостей.

swc — это сверхбыстрый компилятор JavaScript / TypeScript. По сравнению с Babel, он был протестирован на увеличение скорости компиляции как минимум в 18 раз.

Хотите запускать все крутые Flash-игры, для которых Adobe недавно отключила поддержку? Вы можете использовать Ruffle, эмулятор Flash-плеера, написанный на Rust.

Вы можете попробовать это на ruffle.rs.

Сумасшедший

Lunatic — экспериментальная платформа, которая использует экземпляры WASM в качестве субъектов для структурирования выполнения. Он во многом вдохновлен Erlang.

Читать:
В какую сторону момент положительный

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

Звездолет

Starship — это быстрая, настраиваемая и интеллектуальная подсказка для тех, кто хочет сделать свою оболочку круче.

MeiliSearch

MeiliSearch — это мощная, быстрая, простая в использовании и настраиваемая поисковая система, которая также допускает опечатки. А теперь много прилагательных! Вы можете настроить его для своего собственного проекта вместо нестандартного и, возможно, менее производительного решения.

Есть что добавить?

Как видите, экосистема огромна, и есть что исследовать. Я определенно не мог охватить все. Если вы знаете о проекте, который заслуживает быть здесь, не бойтесь сообщить нам об этом в Твиттере!

Если вы хотите узнать больше о Rust, я предлагаю перейти в раздел нашего блога, посвященный Rust. Развлекайся!

Что пишут на rust

Rust невероятно быстр и эффективен по использованию памяти: без рантайма или сборщика мусора он может обеспечить работу критичных для производительности сервисов, запускаться на встраиваемых устройствах и легко интегрироваться с другими языками.

Надёжность

Богатая система типов Rust и модель владения гарантируют потокобезопасность и безопасность памяти, и позволяют устранить множество классов ошибок во время компиляции.

Продуктивность

У Rust отличная документация, дружественный компилятор с полезными сообщениями об ошибках и первоклассный инструментарий — интегрированный пакетный менеджер и инструмент сборки, умная мультиредакторная поддержка с автокомплитом, проверками типов, автоформатированием и многим другим.

Создайте это в Rust

В 2018 году, сообщество Rust приняло решение расширить присутствие языка для нескольких областей (смотрите roadmap на 2018 год). Для этого вы можете найти множество высококачественных пакетов и потрясающие руководства о том, как начать.

Командная строка

Быстро создайте инструмент командной строки с помощью надёжной экосистемы Rust. Rust поможет вам с уверенностью поддерживать ваше приложение и с лёгкостью его распространять.

WebAssembly

Используйте Rust для перезарядки вашего JavaScript, по одному модулю за раз. Опубликуйте в npm, упакуйте с webpack и вы готовы к соревнованиям.

Сетевое программирование

Предсказуемая производительность. Крошечные требования к ресурсам. Потрясающая надёжность. Rust отлично подходит для сетевых сервисов.

Встраиваемые системы

Ориентируетесь на устройства с малой производительностью? Нужен низкоуровневый контроль без отказа от высокоуровневых удобств? Rust предоставит это.

Промышленное использование Rust

Сотни компаний по всему миру используют Rust в реальных проектах для быстрых кросс-платформенных решений с ограниченными ресурсами. Такие проекты, как Firefox, Dropbox и Cloudflare, используют Rust. Rust отлично подходит как для стартапов, так и для больших компаний, как для встраиваемых устройств, так и для масштабируемых web-сервисов.

– Chris Dickinson, инженер npm, Inc

– Antonio Verardi, инженер по инфраструктуре

Примите участие

Читай про Rust

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

Смотрите про Rust

У Rust сообщества есть отдельный канал на YouTube, где собрано огромное количество презентаций и учебных пособий.

Сделать вклад

Rust — действительно работа сообщества, и мы приветствуем вклад как любителей, так и тех, кто использует его в промышленной разработке, от новичков, до профессионалов. Помогите нам улучшить опыт работы с Rust!

Благодарности

Rust не существовал бы без щедрого вклада времени, работы и ресурсов от отдельных лиц и компаний. Мы очень благодарны за поддержку!

Отдельные участники

Rust — это проект сообщества, и он очень благодарен за многочисленные вклады сообщества, которые он получает.

Корпоративные спонсоры

Проект Rust получает поддержку от компаний через пожертвования для инфраструктуры.

Почему вы должны попробовать Rust

Это ознакомительная статья о языке программирования Rust и его инструментах, с помощью которой я надеюсь привлечь ваше внимание к этому интересному и уникальному языку, созданному чтобы дать ответ на следующие вопросы разработчиков:

Как убедиться, что в моем приложении нет проблем и уязвимостей, связанных с неправильной работой с памятью?

Как быть уверенным в том, что любой доступ к общим объектам правильно защищен?

Как свести к минимуму любую работу, не связанную напрямую с написанием кода?

Цель данной статьи не рассказать о доселе невиданных возможностях Rust (сразу говорю, что тут ничего нового «Растоманы» не найдут), на Хабре вы итак найдете множество интересных статей о внутренностях языка и интересных случаев использования. Моя цель рассказать о том, что он предлагает в качестве решения обозначенных выше проблем, как это будет выглядеть со стороны программиста, и почему это важно.

История одного языка

Все началось в 2006 году как персональный проект сотрудника Mozilla — Грейдона Хоара (Graydon Hoare). В 2009 году Грейдон представил свой новый язык программирования коллегам из Mozilla Research, предложив его как перспективную замену C++, поскольку он разрабатывался с приоритетом на безопасность и эффективность создания параллельных приложений (современные браузеры, такие как Mozilla Firefox, являются крупными и очень сложными проектами с не тривиальными алгоритмами параллельной обработки данных). Вскоре, на ежегодном саммите Mozilla 2010, Грейдон представил язык Rust и анонсировал проект Servo (браузерный движок нового поколения). Вначале сообщество разработчиков отнеслось к этой инициативе довольно скептически и некоторые обвиняли Mozilla в синдроме NIH (Not Invented Here). Они назвали его ещё одним бесполезным языком программирования, который умрёт ещё до того, как он станет достаточно популярным, чтобы иметь хоть какое-то значение (вспоминая язык D и его судьбу). Однако дальнейшее развитие событий показало, что это не очередной академический проект для тестирования идей, а полноценный конкурент для таких мастодонтов, как C/C++.

В 2011 г. Rust, используя LLVM, успешно скомпилировал сам себя, а в 2015 году была выпущена первая стабильная версия 1.0. И, наконец, в 2017 году Mozilla выпустила свой первый полноценный проект, написанный на Rust, который был успешно интегрирован в Firefox — Quantum CSS — полностью мультипоточный CSS-движок, в основу которого взят результат разработки прототипа Servo. На этом этапе Mozilla доказала, что язык Rust уже зрелый и обладает достаточной функциональностью для создания больших и сложных production-ready приложений.

Прошло уже больше пяти лет с момента первого стабильного релиза. От изначальной версии Rust, показанной на презентации в 2010 году, уже мало что осталось. Полистав ту презентацию, вы можете легко заметить, что тогда язык был совершенно иным: другой синтаксис, зеленые потоки вместо системных и т.д. Rust сильно изменился во всех аспектах и стал языком программирования общего назначения, который подходит для любых задач. Этот результат был достигнут в основном благодаря открытому и дружелюбному сообществу, создавшему инфраструктуру, статьи, книги, учебные пособия и полезные инструменты. В настоящее время Rust можно применять в любой сфере, независимо от того, является ли проект desktop-приложением, ядром ОС или веб-приложением для облачного сервиса.

В последние годы мнение разработчиков о языке изменилось в положительную сторону. Невероятно, но Rust является самым любимым языком пользователей Stack Overflow уже пять лет подряд! Более того, стали появляться проекты, целиком написанные на Rust, а его присутствие в популярных open-source и коммерческих проектах растет с каждым годом. Например, ripgrep — это проект с открытым исходным кодом для рекурсивного поиска в каталогах с использованием регулярных выражений. Он в 10 раз быстрее, чем GNU grep, и в 4 раза быстрее, чем Silver Searcher. В результате ripgrep был интегрирован в MS Visual Studio Code в качестве средства поиска регулярок по умолчанию. Также, в копилку доказательства хорошей производительности получаемых программ можно добавить результаты The Computer Language Benchmarks Game проекта Debian, где Rust в одной лиге с C/C++.

Сегодня множество технологических компаний выбирают Rust за его производительность, безопасность и эффективность разработки. Позвольте мне привести несколько примеров:

Apple – технологический гигант, который ставит на первое место производительность и безопасность, решил перевести низкоуровневую часть Apple Cloud Traffic на Rust, а новый функционал, по возможности, в первую очередь писать на нем.

Amazon – выбрал Rust для реализации Firecracker – проекта безопасных и быстрых microVM для бессерверных вычислений.

Microsoft – также активно исследует возможность перехода на Rust для низкоуровневых и чувствительных к производительности компонентов. Они уже попробовали в качестве эксперимента переписать некоторые низкоуровневые системные компоненты Windows.

Google – разрешает использовать Rust (кроме kernel части) для реализации своей новой операционной системы Fuchsia.

Mozilla – собирается переписать внутренние компоненты на Rust, чтобы улучшить многопоточную обработку, как часть инициативы сделать Firefox более безопасным и быстрым — Firefox Quantum.

Huawei – также исследует возможности использовать язык Rust в своих будущих проектах.

Список можно продолжить и далее: Dropbox, Facebook, Bitbucket, Discord и т.д. – все эти известные компании начали использовать Rust в частях своих серверных платформ. Обратите внимание, что не только крупные международные компании используют Rust – в нем заинтересованы и стартапы. Например, новая компания, основанная Брайаном Кантриллом (изначальный разработчик dtrace), планирует использовать Rust в качестве основного языка для реализации своего проекта. Немаловажно для всех этих компаний то, что разработчики Rust принимают решения, связанные с дизайном языка, руководствуясь обратной совместимостью и стабильностью кодовой базы.

Но, несмотря на все успехи Rust, колыбель языка Mozilla чувствовала себя не очень хорошо и, в связи с финансовыми трудностями, в 2020 году приступила к отделению проекта в независимую организацию Rust Foundation, серьезно уменьшив свое влияние на развитие языка и отпустив его в свободное плавание. Изначальный список членов организации внушает оптимизм за будущее языка:

Как вы можете видеть, в данный момент Rust является одним из самых любимых и перспективных языков программирования. Было бы ошибкой для программистов просто игнорировать все эти факты и ни разу не попробовать данный язык в деле.

Но что делает Rust таким желанным для многих разработчиков? Давайте немного углубимся в детали и изучим некоторые важные и полезные аспекты языка.

Приоритет безопасности

Если мы хотим создать приложения с минимумом уязвимостей, мы должны обратить пристальное внимание на операции управления памятью. Нарушение безопасности памяти приводит к неожиданному сбою программ и может быть использовано для несанкционированного доступа к данным пользователя. В результате пользователь сталкивается с утечкой данных и удаленным выполнением кода. К таким нарушениям относятся:

Использование памяти после освобождения (Use After Free)

Разыменование нулевого указателя (Null Dereference)

Использование неинициализированной памяти (Using uninitialized variables)

Двойное освобождение (Double Free)

Переполнение буфера (Buffer Overflow)

MSRC Security Research 2019 года (Microsoft) показал, что 70% Common Vulnerabilities and Exposures (CVEs) в их продуктах были связаны с проблемами безопасности памяти в С и С++ (думаю весьма известный график):

Кто-то может сказать, что данный отчет лишь показывает проблемы Microsoft, так как их продукты являются проприетарным программным обеспечением, тогда как продукт с открытым исходным кодом благодаря контролю «тысячи глаз» будет иметь значительно меньше проблем. На самом деле не все так радужно. Взгляните на CVEs за 2019 год (последний из доступных на данном ресурсе), найденные в ядре Linux, разрабатываемом и проверяемом ведущими отраслевыми экспертами:

Как мы видим, open-source сообщество допустили достаточно большое количество уязвимостей, связанных с безопасностью работы с памятью (примерно 65%). Я уверен, вы знаете, что такого рода проблемы тяжело найти и зачастую они проходят мимо глаз. Однако в Rust эти проблемы не могут возникнуть, как говорится, by design (если конечно не использовать unsafe, но это тема для отдельного разговора). И все это достигается на этапе компиляции!

Для этих целей Rust имеет такие элементы языка, как Ownership и Borrowing. Система Ownership является основой для всего языка. Rust гарантирует, что у любого заданного объекта на все время его жизни существует ровно один владелец:

Кроме того, передача объекта в качестве аргумента функции также приведет к передаче права собственности на область действия аргумента функции:

Одним из дополнительных преимуществ Rust является диагностика ошибок в базовом компиляторе. Я уверен, что вам понравятся такие дружелюбные и полезные сообщения об ошибках. В Rust каждое сообщение:

Объясняет, почему проблема произошла;

Выделяет все элементы, которые вызвали проблему;

Дает инструкции о том, как получить больше информации об ошибке, и даже предлагает возможный вариант исправления.

Для примера, посмотрите на это подробное сообщение об ошибке:

Хорошо, а когда освободится выделенная память? В Rust нету GC, поэтому волшебный runtime не придет на помощь. В таких языках как C/C++ разработчик обязан самостоятельно определять, когда пора возвратить память ОС. Данная задача не из тривиальных и требует достаточно высокую квалификацию в сложных проектах. Rust решает эту проблему по-своему: он позволяет хранить данные как в стеке, так и в куче, а память автоматически возвращается, как только переменная, которой она принадлежит, уходит за пределы области видимости:

В Rust можно также заимствовать (borrow) объект, используя ссылку, чтобы избежать излишние изменения владельца и копирования. Однако для этого существуют некоторые строгие ограничения, процитирую:

В любой момент времени вы можете иметь либо одну изменяемую ссылку, либо любое количество неизменяемых ссылок.

Ссылки всегда должны быть актуальными.

Для этой цели Rust отслеживает время жизни (lifetime) для каждой ссылки. Чаще всего времена жизни объектов генерируются автоматически, но в некоторых случаях мы должны аннотировать их вручную, используя специальный синтаксис языка. Это позволяет эффективно управлять памятью без оверхеда от использования GC. Пример заимствования:

А вот так мы можем нарушить озвученные выше ограничения. Но тут приходит borrow checker, и выписывает нам ошибку:

В данном примере мы нарушаем одно из правил языка – в один момент времени разрешена только одна изменяемая ссылка. В этом случае мы получаем следующее сообщение:

Эти ограничения позволяют производить мутации, но в строго контролируемом стиле. Это то, с чем новые разработчики имеют наибольшее количество проблем, потому что такие языки как C/C++ позволяют мутировать объекты без каких-либо ограничений. Все эти правила были введены, чтобы предотвратить одну очень неприятную проблему при разработке многопоточных программ — data race. Но об этом поговорим чуть позже.

Rust — это язык со статической типизацией, который дополнительно имеет следующие особенности:

Разделяет переменные на изменяемые и неизменяемые.

Каждая переменная является неизменяемой по умолчанию и обязательно должна быть проинициализирована актуальным для данного типа значением (например, определенным значением enum).

Не позволяет выполнять неявное приведение типов даже для примитивов.

Проверка границ массивов (небольшая цена производительности для исключения более серьезных проблем).

В debug-режиме компилируется с проверкой integer overflow.

Как некоторые говорят, Rust — это весьма педантичный компилятор и эти неудобства могут немного надоедать, увеличивая время вхождения для новичков. Но эти неудобства языка обязательны для обеспечения безопасности работы с памятью. В ответ мы получаем нечто большее — в Rust (опять же, если не использовать unsafe) невозможны упомянутые выше ошибки: использование памяти после освобождения, разыменование нулевого указателя, использование неинициализированной памяти, двойное освобождение и переполнение буфера.

И под конец главы добавлю, что сами разработчики Rust не только о себе думают, но и активно участвуют в улучшении безопасности проекта LLVM. Например в этом году они в тесной коллаборации с LLVM добавили поддержку защиты от Stack Clash в LLVM/Clang.

Многопоточность без гонок

Последние поколения процессоров склонны наращивать количество ядер. Еще несколько лет назад максимальное количество ядер в корпоративных процессорах составляло 28, но не так давно получили распространение процессоры AMD Epyc и Kunpeng, которые подняли планку до 64 ядер! Это огромная мощность, которую очень трудно использовать эффективно. Максимальное использование ресурсов таких CPUs приводит к тому, что алгоритмы и приложения становятся все более сложными. Исторически, программирование в этом контексте всегда было трудоемким и подвержено ошибкам, поэтому разработчикам нужны инструменты, которые помогут им реализовать свои идеи без головной боли.

Fearless Concurrency — этим термином разработчики Rust называют способность своего языка помогать создавать многопоточные алгоритмы безопасно и эффективно. Давайте начнем с простого примера, как создать поток:

В Rust потоки изолированы друг от друга с помощью системы владения объектом. Записи могут происходить только в том случае, если поток является владельцем данных или имеет изменяемую ссылку. Таким образом, в любой момент времени существует только один поток, который имеет мутабельный доступ к данным. Чтобы ограничить передачу данных между потоками, Rust поддерживает два типажа (traits): Sync и Send. Оба этих типажа реализуются автоматически, когда компилятор определяет, что тип данных соответствуют требованиям. И тут мы уже увидели одну очень приятную особенность Rust: язык различает безопасные и небезопасные типы для передачи данных между потоками .

Send – это типы, которые могут быть безопасно перемещены из одного потока в другой. Например, Arc (Atomic Reference Counter) и String — это типы Send. Один из способов передачи данных между потоками — каналы в стиле Go. Это потокобезопасная операция, и компилятор проверяет, реализует ли объект Send. Вот пример переноса объекта:

Если разработчик попытается переместить объект, не являющийся объектом Send, в другой поток, используя захват переменной замыканием, компилятор Rust выведет нечто подобное:

Sync — типы, на которые можно безопасно ссылаться между потоками. Примитивные типы, такие как целое и число с плавающей запятой, являются Sync. Sync предоставляет иммутабельный доступ к объекту для нескольких потоков одновременно:

В случаях, когда требуется потокобезопасная мутабельность, Rust предоставляет атомарные типы данных и исключающую блокировку через Mutex. Основное преимущество подхода Rust — это то, что нет простого способа получить доступ к объекту без блокировки мьютекса или без использования атомарного типа данных. Например, когда вы создаете мьютекс, вы также передаете в него права на собственность объекта. Метод Lock создает некий smart-pointer MutexGuard на объект внутри мьютекса, через который вы можете получить доступ к объекту в этом потоке, пока у MutexGuard не закончится время жизни:

В Rust наличие изменяемого доступа к объекту гарантирует атомарность его обновления, так как ни один другой поток не может иметь параллельный доступ для чтения. На этом этапе компилятор Rust предотвращает все потенциальные состояния гонки данных во время компиляции, однако результатом такого подхода является увеличение количества неудобств при разработки приложений с многопоточной обработкой, особенно если пытаться обойти unsafe операции. Например, исследователи столкнулись со сложностями при безопасном распараллеливании алгоритмов своими руками, и в итоге решили воспользоваться помощью готовой библиотеки.

Подводя итог, в Rust вам не нужно беспокоиться, что вы где-то забыли защитить данные или обратились неправильно к общим объектам, так как компилятор скажет и укажет вам на все небезопасные операции. Это стало возможным благодаря системе Ownership и грамотной архитектуре ограничения передачи объектов между потоками.

One Tool to Rule Them All

Что мы узнали: Rust — это уникальный язык, который может сделать жизнь разработчиков программного обеспечения проще (или сложнее), а их программы безопаснее (хотя и требует более долгого времени вхождения до начала эффективного применения). Но есть еще один чрезвычайно важный аспект всех языков программирования, который требует отдельного внимания — инструментарий. Давайте вспомним, какой инструментарий используется в C/C++? На самом деле, на это трудно ответить, потому что каждый проект выбирает свой пакетный менеджер, билд-систему, формат документации и систему тестирования. Это вызывает трудности в обслуживании продуктов у мейнтейнеров.

Разработчики Rust знают об этой ситуации и понимают, что они должны обязательно предложить нечто лучшее, чтобы обеспечить все необходимые функции и уменьшить трату времени на задачи, которые не связаны непосредственно с разработкой продукта. Результат их работы они назвали Cargo. Cargo поставляется вместе с Rust и используется почти в каждом проекте (хотя без него вы все еще можете использовать компилятор rustc, как любой другой компилятор C/C++). Этот менеджер берет все процедуры обслуживания на себя и помогает вам создавать проекты, управлять зависимостями, собирать приложение, создавать документацию и тестировать проект.

Итак, давайте посмотрим, как это выглядит. Во-первых, нам нужно создать наш новый замечательный проект, просто введя следующую команду:

Cargo создаст каталог со следующими файлами:

Как мы видим, Cargo создал git репозиторий, каталог с исходниками, TOML-файл, содержащий конфигурацию проекта, и некоторые служебные файлы. Самый интересный файл TOML. Здесь хранятся все настройки проекта, включая имя проекта, версию, список зависимостей, флаги для компилятора и другие классные вещи. Его легко читать и редактировать, а так же централизовано управлять релизами. Пример содержания файла после инициализации:

Далее, давайте напишем простенькую программу:

Это все, что требуется от разработчика, чтобы собрать проект со всеми зависимостями. И, самое главное, при росте проекта сложность управления не сильно изменится благодаря продуманной структуре проекта и инструментов. Cargo проверяет все изменения, сканирует зависимости и обновляет их при необходимости, используя для конфигурации TOML файл.

Тестирование

Rust и Cargo уже имеют все, что нужно для написания тестов без каких-либо внешних инструментов. Вкратце, тест в Rust — это функция, аннотированная атрибутом #[test] . Давайте для примера создадим тестовую функцию, добавив несколько строк кода в main.rs:

Готово! Теперь запускаем:

С помощью атрибута #[cfg(test)] можно создать отдельный подмодуль со всеми нужными вспомогательными функциями для тестов который будут использоваться только во время тестирования.

Документация

Cargo предоставляет продвинутые инструменты для создания интерактивной документации с богатыми возможностями форматирования. Rust имеет особые комментарии ( /// — тройная косая черта) для документации, которые известны как комментарии к документации с markdown нотацией, которые будут использоваться для генерации HTML-документов. В этом примере мы добавили некоторую информацию о функции add() и собрали соответствующую документацию:

И собираем документацию одной простой командой:

В результате мы получаем HTML-страницы с гиперссылками, подсветкой синтаксиса и поисковой системой:

Внешние зависимости

В Rust единица компиляции называется «crate» и может быть либо библиотекой, либо исполняемой программой.

Например, нам нужно проанализировать некоторые JSON-файлы, но мы не хотим делать это с нуля. В этом случае мы идем на постоянно растущий crates.io репозиторий и ищем подходящий crate для нас. Отлично! Мы нашли Serde — библиотека для сериализации и десериализации структур данных. Давайте попробуем импортировать ее с поддержкой json в наш проект с помощью TOML-файла:

И вызываем команду сборки проекта:

Cargo проверил все зависимости, загрузил их и собрал. Теперь вы можете пользоваться библиотекой напрямую! Раздел [dependencies] — это место, где вы сообщаете Cargo требуемые крейты и их версии. В этом примере мы задаем семантический спецификатор версии 1.0.53. Cargo понимает Semver нотацию, и это фактически означает «любую версию, совместимый с версией 1.0.53». Для обновления крейтов до новой версии достаточно воспользоваться командой cargo update . Кроме того, любой может поделиться своими собственным крейтом на crates.io, и вы можете это сделать лишь парой команд! С помощью крейтов можно установить дополнительные инструменты в рабочее пространство (например, ripgrep) для различных целей вашего проекта. Вдобавок, вы можете установить свой собственный сервер crate.io в сети вашей организации и быть независимыми от внешних поставщиков. Короче говоря, замечательный инструмент, который делает разработку на Rust такой гладкой и беспроблемной.

Среды разработки

Последнее, но не менее важное, о чем я хочу вам рассказать — это rust-analyzer (будущий преемник RLS), предоставляющий поддержку Rust в различных средах разработки. В данный момент, с использованием rust-analyzer или своей собственной реализации анализатора, уже поддерживаются следующие IDE и редакторы: vim, emacs, MS Visual Studio Code, IntelliJ Idea и т.д. Они имеют все необходимые функции для эффективного написания кода, такие как: дополнение кода, вывод документации и подсветка ошибок. Количество поддерживаемых интегрированных сред достаточно велико, чтобы вы могли себя чувствовать, как дома.

Эпилог

Если вы уже заинтересованы в этом языке, существует очень подробное учебное пособие. И, если вы хотите углубиться в особенности языка, статьи о темных и сложных сторонах Rust — Rustonomicon. Как вы видите Rust весьма интересный язык с дружелюбными инструментами и с приоритетом безопасности, но со своими нюансами, поэтому, чтобы оценить его достоинства и недостатки я бы предложил вам просто попробовать Rust в своем личном проекте, и, возможно, вы станете еще одним из поклонников этого языка.

Похожие статьи