[Перевод] Выпуск Rust 1.31 и Rust 2018

habr.png

Команда разработчиков Rust рада сообщить о выпуске новой версии Rust, 1.31.0, а также «Rust 2018». Rust — это язык программирования, который дает возможность каждому создавать надежное и эффективное программное обеспечение.

Если у вас установлена предыдущая версия Rust с помощью rustup, то для обновления Rust до версии 1.31.0 вам достаточно выполнить:

$ rustup update stable

Если у вас еще не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта. С подробными примечаниями к выпуску Rust 1.31.0 можно ознакомиться на GitHub.


Что вошло в стабильную версию 1.31.0

Rust 1.31, возможно, самый значительный выпуск со времен Rust 1.0! В данный выпуск включена первая итерация «Rust 2018», но это не единственное нововведение! Обзор улучшений будет длинный, поэтому вот оглавление:


  • Rust 2018
    • Нелексические времена жизни
    • Изменения системы модулей
  • Дополнительные правила вывода времен жизни
  • const fn
  • Новые инструменты
  • Инструментальные проверки качества кода
  • Документация
  • Предметные рабочие группы
  • Новый веб-сайт
  • Стабилизация стандартной библиотеки
  • Улучшения в Cargo
  • Разработчики выпуска


Rust 2018

Мы писали о Rust 2018 впервые в марте, и затем в июле. За подробностями зачем нужен Rust 2018, обратитесь к этим публикациям. В данном обзоре нам и так много что нужно рассказать, поэтому мы сосредоточимся только на том, что такое Rust 2018. Также об этом можно почитать в посте на Mozilla Hacks (перевод).

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


  • Инструментарий (поддержка в IDE, rustfmt, Clippy)
  • Документацию
  • Работу предметных рабочих групп
  • Новый веб-сайт

Дальше мы расскажем обо всем этом подробнее и о других нововведениях.

Давайте создадим новый проект с помощью Cargo:

$ cargo new foo

Вот содержимое Cargo.toml:

[package]
name = "foo"
version = "0.1.0"
authors = ["Your Name "]
edition = "2018"

[dependencies]

В секцию [package] был добавлен новый ключ: edition. Обратите внимание, что он установлен в 2018. Вы также можете установить его в 2015 — это значение будет установлено по умолчанию, если ключ отсутствует.

С использованием Rust 2018 будут разблокированы некоторые новые возможности, которые не разрешены в Rust 2015.

Важно отметить, что каждый пакет может быть в режиме 2015 или 2018, и они будут работать вместе. Ваш проект 2018 редакции может использовать зависимости 2015 редакции, а проект 2015 редакции может использовать зависимости 2018 редакции. Это гарантирует целостность экосистемы и что все новые возможности будут опциональны, сохраняя совместимость с существующим кодом. Кроме того, когда вы решите перенести код Rust 2015 на Rust 2018, изменения могут быть внесены автоматически через cargo fix.

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


Нелексические времена жизни

Если вы следили за развитием Rust последние несколько лет, то вы могли время от времени встречать термин «NLL» или «нелексические времена жизни» («non-lexical lifetimes»). Это — жаргонизм, который, если говорить простыми словами, означает: анализатор заимствований стал умнее и теперь принимает некоторый корректный код, который до этого отклонял. Рассмотрим пример:

fn main() {
    let mut x = 5;

    let y = &x;

    let z = &mut x;
}

Раньше Rust выдавал ошибку компиляции:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:18
  |
4 |     let y = &x;
  |              - immutable borrow occurs here
5 |     
6 |     let z = &mut x;
  |                  ^ mutable borrow occurs here
7 | }
  | - immutable borrow ends here

Это потому, что область жизни ссылок определялась «лексически»; то есть, заимствование y считалось активным, пока y не выйдет из области видимости в конце main, даже если мы никогда больше не используем y внутри области. С кодом выше все в порядке, но анализатор зависимостей не мог этого понять.

Теперь этот код замечательно компилируется.

Но что, если бы мы использовали y? Например так:

fn main() {
    let mut x = 5;
    let y = &x;
    let z = &mut x;

    println!("y: {}", y);
}

Раньше Rust выдавал вам такую ошибку:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:18
  |
4 |     let y = &x;
  |              - immutable borrow occurs here
5 |     let z = &mut x;
  |                  ^ mutable borrow occurs here
...
8 | }
  | - immutable borrow ends here

В Rust 2018 это сообщение об ошибке улучшилось:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:13
  |
4 |     let y = &x;
  |             -- immutable borrow occurs here
5 |     let z = &mut x;
  |             ^^^^^^ mutable borrow occurs here
6 |     
7 |     println!("y: {}", y);
  |                       - borrow later used here

Вместо того, чтобы указывать, где y выходит из области видимости, оно показывает, где происходит конфликтное заимствование. Это значительно упрощает отладку ошибок такого рода.

В Rust 1.31 это улучшение исключительно для Rust 2018. Мы планируем добавить его в Rust 2015 позже.


Изменения системы модулей

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

Поэтому редакция 2018 вносит некоторые изменения в то, как работают пути, упрощая систему модулей и делая ее понятнее.

Вот краткое резюме:


  • extern crate больше не требуется практически нигде.
  • Вы можете импортировать макросы с помощью use, вместо использования атрибута #[macro_use].
  • Абсолютные пути начинаются с имени контейнера, где ключевое слово crate относится к текущему контейнеру.
  • foo.rs и поддиректория foo/ могут сосуществовать; mod.rs больше не требуется при размещении подмодулей в поддиректории.

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

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


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

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

impl<'a> Reader for BufReader<'a> {
    // здесь методы
}

может быть теперь записан так:

impl Reader for BufReader<'_> {
    // здесь методы
}

Время жизни '_ по-прежнему показывает, чтоBufReader принимает его как параметр, но нам больше не нужно задавать для него имя.

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

// Rust 2015
struct Ref<'a, T: 'a> {
    field: &'a T
}

// Rust 2018
struct Ref<'a, T> {
    field: &'a T
}

Зависимость : 'a будет выведена. Вы все еще можете указать ее явно, если хотите. Мы рассматриваем и другие возможности для вывода в подобных местах на будущее, но пока не имеем конкретных планов.


const fn

В Rust есть несколько способов объявления функции: fn для обычных функций, unsafe fn для небезопасных функций и extern fn для внешних функций. В этом выпуске добавлен новый способ объявления функции: const fn. Он используется так:

const fn foo(x: i32) -> i32 {
    x + 1
}

Константная функция может вызываться как обычная функция, но помимо этого она может использоваться в любом константном контексте. При этом она выполнится во время компиляции, а не во время выполнения программы. Например:

const SIX: i32 = foo(5);

Функция foo выполнится во время компиляции и SIX примет значение 6.

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


  • Использовать целочисленные арифметические операции и операции сравнения
  • Использовать любые логические операции, кроме && и ||
  • Конструировать массивы, структуры, перечисления и кортежи
  • Вызывать другие константные функции
  • Обращаться по индексу в массивах и срезах
  • Обращаться к полям структур и кортежей
  • Использовать константы (но не статические значения, и даже не ссылки на них)
  • Использовать & и * ссылки
  • Приводить типы, исключая приведение сырого указателя к целочисленному значению

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

Подробности смотрите в справочнике.


Новые инструменты

Редакция 2018 знаменует начало нового уровня зрелости экосистемы инструментов Rust. Cargo, Rustdoc и Rustup были основными инструментами, начиная с версии 1.0; с редакцией 2018 приходит новое поколение инструментов, которыми теперь все могут пользоваться: Clippy, Rustfmt и поддержка IDE.

Статический анализатор кода clippy теперь доступен в стабильном Rust. Вы можете установить его через rustup component add clippy и запустить командой cargo clippy. Clippy теперь получил версию 1.0 и имеет такие же гарантии стабильности статических проверок, что и rustc. Новые проверки могут добавляться, или может расширяться функционал старых, но старые не могут быть удалены (могут быть только помечены как устаревшие). Это означает, что код, который компилируется с clippy, будет продолжать компилироваться с clippy (при условии, что для проверок не задано генерировать
ошибку через deny), но может выдавать новые предупреждения.

Rustfmt — это инструмент для форматирования кода в Rust. Автоматическое форматирование кода позволит вам сэкономить время, кроме того, оно приблизит ваш код к официальному стилю Rust. Вы можете установить его через rustup component add rustfmt и использовать командой cargo fmt.

Текущий выпуск включает Rustfmt 1.0. Отныне мы гарантируем обратную совместимость для Rustfmt: если вы отформатируете свой код сегодня, то форматирование не изменится в будущем (только для параметров по умолчанию). Обратная совместимость означает, что теперь практично запускать Rustfmt на вашем CI (используйте cargo fmt --check). Попробуйте это вместе с «форматированием при сохранении» в редакторе, и ваш рабочий процесс революционизируется.

Поддержка IDE — одна из самых востребованных возможностей инструментов для Rust. Сейчас имеется несколько решений высокого качества:

Работа по поддержке в IDE не закончена. В частности, автодополнение кода в редакторах, основанных на RLS, не на высоте. Однако, если вы в основном хотите поддержку типов, документации и «перехода к определению», то вы останетесь довольны.


Инструментальные проверки качества кода (tool lints)

В Rust 1.30 мы стабилизировали «инструментальные атрибуты», такие как #[rustfmt::skip]. В Rust 1.31 мы стабилизировали нечто подобное: «инструментальные проверки качества кода» («tool lints»), такие как #[allow(clippy::bool_comparison)]. Это позволяет задавать пространства имен для проверок, чтобы стало понятнее, из каких инструментов они берутся.

Если вы ранее использовали проверки Clippy, вы можете выполнить миграцию следующим образом:

// было
#![cfg_attr(feature = "cargo-clippy", allow(bool_comparison))]

// стало
#![allow(clippy::bool_comparison)]

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


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

В Rustdoc было несколько улучшений в этом году, и была выпущена полностью переписанная книга «The Rust Programming Language». Вы можете купить бумажную копию от No Starch Press!

Раньше ее называли «вторым изданием» книги, но, так как она стала первым печатным изданием, то это вызвало путаницу. Ведь и печатное издание планируется периодически обновлять. В конце концов, после множества дискуссий с No Starch, было решено обновлять книгу на веб-сайте вместе с каждым выпуском, а No Starch будет периодически забирать изменения и печатать их. Книга довольно хорошо продается и собирает деньги для Black Girls Code.

Вы можете найти новую версию книги здесь.


Предметные рабочие группы

В этом году мы объявили о создании четырех рабочих групп:


  • Сетевые сервисы
  • Приложения командной строки
  • WebAssembly
  • Встроенные устройства

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


  • В сетевых сервисах переработали интерфейс для Futures, а сверх этого еще и async/await. Эти улучшения еще не выпущены, но мы уже близки к этому!
  • Команда CLI работала над библиотеками и документацией, чтобы сделать приложения командной строки лучше.
  • Группа WebAssembly выпустила множество инструментов мирового уровня для использования Rust с wasm.
  • Для встроенных устройств появилась возможность вести разработку ARM на стабильном Rust!

Обо всем этом подробнее можно узнать на нашем новом сайте!


Новый веб-сайт

На прошлой неделе мы анонсировали новую версию нашего веб-сайта. Теперь она стала официальной версией rust-lang.org!

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


Стабилизация стандартной библиотеки

Были добавлены новые реализации From:


  • u8 теперь реализует From, аналогично и для других числовых типов и их NonZero эквивалентов
  • Option<&T> реализует From<&Option>, аналогично и для &mut

Также были стабилизированы следующие функции:

Подробности смотрите в примечаниях к выпуску.


Улучшения в Cargo

Cargo теперь будет загружать пакеты параллельно, используя HTTP/2.

Кроме того, так как extern crate указывать теперь не обязательно, было бы неприятно писать extern crate foo as bar; для переименования зависимости. Поэтому вы можете делать это в Cargo.toml таким образом:

[dependencies]
baz = { version = "0.1", package = "foo" }

или, что эквивалентно:

[dependencies.baz]
version = "0.1"
package = "foo"

Теперь пакет foo доступен как baz для использования в вашем коде.

Подробности смотрите в примечаниях к выпуску.


Разработчики 1.31.0

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

От переводчика: выражаю отдельную благодарность участникам сообщества Rustycrate и лично ozkriff, humbug и mvlabat за помощь с переводом и вычиткой.

© Habrahabr.ru