Недавний опрос Stack Overflow показал, что многим разработчикам нравится разрабатывать или они хотят начать писать программы на языке Rust. Это невероятная цифра!
Что же такого хорошего в Rust? В этой статье мы рассмотрим лучшие стороны этого языка и покажем, почему он должен быть следующим в вашем списке языков для изучения.
Происхождение Rust
Во-первых, давайте начнем с краткого урока истории. Rust — новый язык по отношению к своим предшественникам , но его генеалогия создает свой мультипарадигмальный подход. Rust считается Си-подобным языком, но другие функции, которые он включает, создают преимущества по сравнению с его предшественниками
Во-вторых, на Rust сильно повлиял Cyclone (императивный язык), с некоторыми аспектами объектно-ориентированных функций из C++
. Но он также включает в себя функциональные возможности таких языков, как Haskell и OCaml. В результате получается C
-подобный язык, поддерживающий мультипарадигмальное программирование (императивное, функциональное и объектно-ориентированное).
Рисунок 1. Rust и его генеалогическое древо
Ключевые понятия в Rust
Rust имеет много функций, которые делают его полезным, но разработчики и их потребности различаются. Я расскажу о пяти ключевых концепциях, которые делают Rust достойным изучения, и покажу эти идеи в исходном коде Rust.
Во-первых, чтобы получить представление о коде, давайте посмотрим на каноническую программу «Hello World», которая просто отправляет это сообщение пользователю (см. листинг 1 ).
Листинг 1. «Hello World» в Rust
fn main() { println!( "Hello World."); }
Эта простая программа, похожая на C
, определяет основную функцию, которая является назначенной точкой входа для программы (и она есть в каждой программе). Функция определяется ключевым словом, fn
за которым следует необязательный набор параметров в скобках ( ()
). Фигурные скобки ( {}
) определяют функцию; эта функция состоит из вызова макроса println!
, который выводит форматированный текст на консоль ( stdout
), как определено строковым параметром.
Rust включает в себя множество функций, которые делают его интересным и стоящим инвестиций в его изучение. Вы найдете такие концепции, как модули для повторного использования, безопасность памяти и гарантии (безопасные и небезопасные операции), неисправимые и восстанавливаемые функции обработки ошибок, поддержку параллелизма и сложные типы данных (называемые коллекциями).
Повторно используемый код через модули
Rust позволяет организовать код таким образом, чтобы способствовать его повторному использованию. Вы достигаете такой организации, используя модули, которые содержат функции, структуры и даже другие модули, которые вы можете сделать общедоступными (то есть доступными для пользователей модуля) или частными (то есть использовать только внутри модуля, а не самим модулем). пользователей — по крайней мере, не напрямую). Модуль организует код как пакет, который могут использовать другие.
Вы используете три ключевых слова для создания модулей, использования модулей и изменения видимости элементов в модулях.
- Ключевое
mod
слово создает новый модуль - Ключевое
use
слово позволяет вам использовать модуль (раскройте определения в области видимости, чтобы использовать их) - Ключевое
pub
слово делает элементы модуля общедоступными (в противном случае они являются частными).
В листинге 2 приведен простой пример. Он начинается с создания нового модуля с именем bits
, который содержит три функции. Первая функция, называемая pos
, является закрытой функцией, которая принимает u32
аргумент и возвращает значение u32
(как показано стрелкой ->
), которое представляет собой 1-кратное значение, сдвинутое влево bit
. Обратите внимание, что return
ключевое слово здесь не требуется. Это значение вызывается двумя общедоступными функциями (обратите внимание на pub
ключевое слово): decimal
и hex
. Эти функции вызывают частную pos
функцию и печатают значение позиции бита в десятичном или шестнадцатеричном формате (обратите внимание на использование :x
для указания шестнадцатеричного формата). Наконец, он объявляет main
функцию, которая вызываетbits
две общедоступные функции модуля с выводом, показанным в конце листинга 2 в виде комментариев.
Листинг 2. Пример простого модуля на Rust
mod bits { fn pos(bit: u32) ‑> u32 { 1 << bit } pub fn decimal(bit: u32) { println!("Bits decimal {}", pos(bit)); } pub fn hex(bit: u32) { println!("Bits decimal 0x{:x}", pos(bit)); } } fn main( ) { bits::decimal(8); bits::hex(8); } // Bits decimal 256 // Bits decimal 0x100
Модули позволяют вам собирать функциональные возможности общедоступными или частными способами, но вы также можете связать методы с объектами, используя ключевое impl
слово.
Проверки безопасности для более чистого кода
Компилятор Rust обеспечивает гарантии безопасности памяти и другие проверки, которые делают язык программирования безопасным (в отличие от C
, который может быть небезопасным). Таким образом, в Rust вам никогда не придется беспокоиться о оборванных указателях или использовании объекта после того, как он был освобожден. Эти вещи являются частью основного языка Rust. Но в таких областях, как разработка встраиваемых систем, важно делать такие вещи, как размещение структуры по адресу, представляющему набор аппаратных регистров.
В Rust есть unsafe
ключевое слово, с помощью которого вы можете отключить проверки, которые обычно приводят к ошибке компиляции. Как показано в листинге 3 , unsafe
ключевое слово позволяет объявить небезопасный блок. В этом примере я объявляю неизменяемую переменную x
, а затем указатель на эту переменную с именем raw
. Затем, чтобы отменить ссылку raw
(что в данном случае выведет 1 на консоль), я использую unsafe
ключевое слово, чтобы разрешить эту операцию, которая в противном случае была бы помечена при компиляции.
Листинг 3. Небезопасные операции в Rust
fn main() { let a = 1; let rawp = &a as const i32; unsafe { println!("rawp is {}", rawp); } }
Вы можете применить unsafe
ключевое слово к функциям, а также к блокам кода внутри функции Rust. Ключевое слово чаще всего используется при написании привязок к функциям, отличным от Rust. Эта функция делает Rust полезным для таких вещей, как разработка операционной системы или встроенное (голое железо) программирование.
Улучшенная обработка ошибок
Ошибки случаются независимо от используемого языка программирования. В Rust ошибки делятся на два лагеря: неустранимые ошибки (плохие) и исправимые ошибки (не такие уж плохие).
Неисправимые ошибки
Функция Rust panic!
похожа на C
макрос assert
. Он генерирует выходные данные, чтобы помочь пользователю отладить проблему (а также остановить выполнение до того, как произойдут более катастрофические события). Функция panic!
показана в листинге 4 , а ее исполняемый вывод указан в комментариях.
Листинг 4. Паническая обработка неисправимых ошибок в Rust!
fn main() { panic!("Bad things happening."); } // thread 'main' panicked at 'Bad things happening.', panic.rs:2:4 // note: Run with RUST_BACKTRACE=1 for a backtrace.
Из вывода видно, что среда выполнения Rust точно указывает, где возникла проблема (строка 2), и выдает предоставленное сообщение (которое может выдавать более описательную информацию). Как указано в выходном сообщении, вы можете сгенерировать обратную трассировку стека, запустив специальную переменную среды с именем RUST_BACKTRACE
. Вы также можете вызывать panic!
внутренне на основе обнаруживаемых ошибок (таких как доступ к недопустимому индексу вектора).
Устранимые ошибки
Обработка исправимых ошибок — стандартная часть программирования, и в Rust есть удобная функция проверки ошибок (см. листинг 5 ). Взгляните на эту функцию в контексте операции с файлом. Функция File::open
возвращает тип Result<T, E>
, где T и E представляют параметры универсального типа (в данном контексте они представляют std::fs::File
и std::io::Error
). Итак, когда вы звоните File::open
и не произошло ошибки ( E
is Ok
), T
будет представлять тип возвращаемого значения ( std::fs::File
). Если произошла ошибка, E
будет представлять тип возникшей ошибки (используя тип std::io::Error
). (Обратите внимание, что в моей файловой переменной _f
используется символ подчеркивания [_
], чтобы опустить предупреждение о неиспользуемой переменной, сгенерированное компилятором.)
Затем я использую специальную функцию в Rust под названием match
, которая похожа на switch
оператор в , C
но более мощная. В этом контексте я сопоставляю _f
возможные значения ошибок ( Ok
и Err
). Для Ok
, я возвращаю файл для присвоения; для Err
, я использую panic!
.
Листинг 5. Обработка исправимых ошибок в Rust с помощью Result<t, e>
use std::fs::File; fn main() { let _f = File::open("file.txt"); let _f = match _f { Ok(file) => file, Err(why) => panic!("Error opening the file {:?}", why), }; } // thread 'main' panicked at 'Error opening the file Error { repr: Os // { code: 2, message: "No such file or directory" } }', recover.rs:8:23 // note: Run with RUST_BACKTRACE=1 for a backtrace.
Установка Rust и его инструментов
Один из самых простых способов установить Rust — использовать curl
скрипт установки. Просто выполните следующую строку из командной строки Linux®:
curl -sSf https://static.rust-lang.org/rustup.sh | sh
Эта строка передает rustup
сценарий оболочки с rust-lang.org, а затем передает сценарий оболочке для выполнения. По завершении вы можете выполнить rustc -v
, чтобы показать версию Rust, которую вы установили. Установив Rust, вы можете поддерживать его с помощью rustup
утилиты, которую вы также можете использовать для обновления вашей установки Rust.
Компилятор Rust называется rustc
. В показанных здесь примерах процесс сборки просто определяется как:
rustc threads.rs
… где компилятор rust создает собственный исполняемый файл с именем threads
. Вы можете символически отлаживать программы на Rust, используя либо , rust-lldb
либо rust-gdb
.
Вы, наверное, заметили, что программы на Rust, которые я здесь продемонстрировал, имеют уникальный стиль. Вы можете изучить этот стиль через автоматическое форматирование исходного кода Rust с помощью rustfmt
утилиты. Эта утилита, запускаемая с именем исходного файла, автоматически форматирует ваш исходный код в соответствии со стандартным стилем.
Наконец, хотя Rust довольно строг в отношении того, что он принимает за исходный код, вы можете использовать программу rust-clippy
, чтобы углубиться в свой исходный код, чтобы выявить элементы плохой практики. Думайте об этом rust-clippy
как об C lint
утилите.
Рекомендации по Windows
В Windows для Rust дополнительно требуются C++
инструменты сборки для Visual Studio 2013 или более поздней версии. Самый простой способ приобрести инструменты сборки — установить Microsoft Visual C++ Build Tools 2017 , который предоставляет только инструменты сборки Visual C++. Кроме того, вы можете установить Visual Studio 2017, Visual Studio 2015 или Visual Studio 2013 и во время установки выбрать инструменты C++ .
Для получения дополнительной информации о настройке Rust в Windows см. документацию по rustup для Windows .