Хабрахабр

[Перевод] Выпуск Rust 1.30

30. Команда разработчиков Rust рада сообщить о выпуске новой версии Rust: 1. Rust — это системный язык программирования, нацеленный на безопасность, скорость и параллельное выполнение кода. 0.

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

$ rustup update stable

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

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

30 — выдающийся выпуск с рядом важных нововведений. Rust 1. 31, которая станет первым релизом "Rust 2018". Но уже в понедельник в официальном блоге будет опубликована просьба проверить бета-версию Rust 1. Дополнительную информацию об этом вы найдете в нашей предыдущей публикации "What is Rust 2018".

Процедурные макросы

15 мы добавили возможность определять "пользовательские derive-макросы". Еще в Rust 1. Например, с помощью serde_derive, вы можете объявить:

#[derive(Serialize, Deserialize, Debug)]
struct Pet { name: String,
}

Это возможно благодаря автоматическому выводу типажей Serialize и Deserialize с помощью процедурных макросов в serde_derive. И конвертировать Pet в JSON и обратно в структуру, используя serde_json.

30 расширяет функционал процедурных макросов, добавляя возможность определять еще два других типа макросов: "атрибутные процедурные макросы" и "функциональные процедурные макросы". Rust 1.

Это делает их более гибкими: derive-макросы работают только для структур и перечислений, но атрибуты могут применяться и к другим объектам, таким как функции. Атрибутные макросы подобны derive-макросам для автоматического вывода, но вместо генерации кода только для атрибута #[derive], они позволяют пользователям создавать собственные новые атрибуты. Например, атрибутные макросы позволят вам при использовании веб-фреймворка делать следующее:

#[route(GET, "/")]
fn index() {

Его сигнатура будет выглядеть так: Этот атрибут #[route] будет определен в самом фреймворке как процедурный макрос.

#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {

Второй — это тело того объекта, к которому применен атрибут. Здесь у нас имеется два входных параметра типа TokenStream: первый — для содержимого самого атрибута, то есть это параметры GET, "/". В нашем случае — это fn index() и остальная часть тела функции.

Например, макрос sql!: Функциональные макросы определяют такие макросы, использование которых выглядит как вызов функции.

let sql = sql!(SELECT * FROM posts WHERE id=1);

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

#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {

Это похоже на сигнатуру derive-макроса: мы получаем токены, которые находятся внутри скобок, и возвращаем сгенерированный по ним код.

Макросы и use

Например, для использования макроса json из пакета serde-json, раньше использовалась запись: Теперь можно импортировать макросы в область видимости с помощью ключевого слова use.

#[macro_use]
extern crate serde_json; let john = json!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ]
});

А теперь вы должны будете написать:

extern crate serde_json; use serde_json::json; let john = json!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ]
});

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

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

#[derive(Serialize)]
struct Demo { ok: String, bad: std::thread::Thread,
}

приводило к такой ошибке:

error[E0277]: the trait bound `std::thread::Thread: _IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not satisfied --> src/main.rs:3:10 |
3 | #[derive(Serialize)] | ^^^^^^^^^ the trait `_IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not implemented for `std::thread::Thread`

Теперь же будет выдано:

error[E0277]: the trait bound `std::thread::Thread: serde::Serialize` is not satisfied --> src/main.rs:7:5 |
7 | bad: std::thread::Thread, | ^^^ the trait `serde::Serialize` is not implemented for `std::thread::Thread`

Улучшение системы модулей

Настоящие изменения являются первым шагом, который мы предпринимаем на пути упрощения системы модулей. Система модулей долгое время становилась больным местом для новичков в Rust'е; некоторые из ее правил оказывались неудобными на практике.

Во-первых, внешние пакеты теперь добавляются в prelude, то есть: В дополнении к вышеупомянутому изменению для макросов, есть два новых улучшения в использовании use.

// было
let json = ::serde_json::from_str("..."); // стало
let json = serde_json::from_str("...");

Подвох в том, что старый стиль не всегда был нужен из-за особенностей работы системы модулей Rust:

extern crate serde_json; fn main() { // это прекрасно работает; мы находимся в корне пакета, поэтому `serde_json` // здесь в области видимости let json = serde_json::from_str("...");
} mod foo { fn bar() { // это не работает; мы внутри пространства имен `foo`, и `serde_json` // здесь не объявлен let json = serde_json::from_str("..."); } // одно решение - это импортировать его внутрь модуля с помощью `use` use serde_json; fn baz() { // другое решение - это использовать `::serde_json`, когда указывается // абсолютный путь, вместо относительного let json = ::serde_json::from_str("..."); }
}

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

Наконец, use стал поддерживать импорт элементов в текущую область видимости с путями, которые начинаются на crate:

mod foo { pub fn bar() { // ... }
} // было
use ::foo::bar;
// или
use foo::bar; // стало
use crate::foo::bar;

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

mod foo { pub fn bar() { // ... }
} mod baz { pub fn qux() { // было ::foo::bar(); // не работает, в отличии от `use`: // foo::bar(); // стало crate::foo::bar(); }
}

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

В любом месте, где вы видите путь a::b::c, кроме оператора use, вы можете спросить: Все эти изменения в совокупности упрощают понимание того, как разрешаются пути.

  • Является ли a именем пакета? Тогда нужно искать b::c внутри него.
  • Является ли a ключевым словом crate? Тогда нужно искать b::c от корня текущего пакета.
  • В противном случае, нужно искать a::b::c от текущего положения в иерархии модулей.

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

Сырые идентификаторы

Вы можете теперь использовать ключевые слова как идентификаторы, используя следующий новый синтаксис:

// определение локальной переменной с именем `for`
let r#for = true; // определение функции с именем `for`
fn r#for() { // ...
} // вызов той функции r#for();

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

Приложения без стандартной библиотеки

6 мы объявили о стабилизации "no_std" и libcore для создания проектов без стандартной библиотеки. Еще в Rust 1. Однако, с одним уточнением: можно было создавать только библиотеки, но не приложения.

30 можно использовать атрибут #[panic_handler] для самостоятельной реализации паники. В Rust 1. Это означает, что теперь можно создавать приложения, а не только библиотеки, которые не используют стандартную библиотеку.

Другое

Дополнительно, "инструментальные атрибуты", такие как #[rustfmt::skip], теперь стабилизированы. И последнее: в макросах теперь можно сопоставлять модификаторы области видимости, такие как pub, с помощью спецификатора vis. Правда для использования с инструментами статического анализа, наподобие #[allow(clippy::something)], они еще не стабильны.

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

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

В этом выпуске были стабилизированы следующие API:

  • Ipv4Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}
  • Ipv6Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}
  • Iterator::find_map

Однако, для RTL-языков значение "справа" и "слева" тут приводят к путанице. Кроме того, стандартная библиотека уже давно имеет функции для удаления пробелов с одной стороны некоторого текста, такие как trim_left. Поэтому мы вводим новые имена для этих функций:

  • trim_left -> trim_start
  • trim_right -> trim_end
  • trim_left_matches -> trim_start_matches
  • trim_right_matches -> trim_end_matches

33. Мы планируем объявить устаревшими старые имена (но не удалить, конечно) в Rust 1.

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

Улучшения в Cargo

Самое большое улучшение Cargo в этом выпуске заключается в том, что теперь у нас есть индикатор выполнения!

demo gif

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

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

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

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

Теги
Показать больше

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть