- PVSM.RU - https://www.pvsm.ru -
Команда разработчиков Rust рада сообщить о выпуске новой версии Rust: 1.30.0. Rust — это системный язык программирования, нацеленный на безопасность, скорость и параллельное выполнение кода.
Если у вас установлена предыдущая версия Rust с помощью rustup
, то для обновления Rust до версии 1.30.0 вам достаточно выполнить:
$ rustup update stable
Если у вас еще не установлен rustup
, вы можете установить его [1] с соответствующей страницы нашего веб-сайта. С подробными примечаниями к выпуску Rust 1.30.0 [2] можно ознакомиться на GitHub.
Rust 1.30 — выдающийся выпуск с рядом важных нововведений. Но уже в понедельник в официальном блоге будет опубликована просьба проверить бета-версию Rust 1.31, которая станет первым релизом "Rust 2018". Дополнительную информацию об этом вы найдете в нашей предыдущей публикации "What is Rust 2018" [3].
Еще в Rust 1.15 [4] мы добавили возможность определять "пользовательские derive-макросы". Например, с помощью serde_derive
, вы можете объявить:
#[derive(Serialize, Deserialize, Debug)]
struct Pet {
name: String,
}
И конвертировать Pet
в JSON и обратно в структуру, используя serde_json
. Это возможно благодаря автоматическому выводу типажей Serialize
и Deserialize
с помощью процедурных макросов в serde_derive
.
Rust 1.30 расширяет функционал процедурных макросов, добавляя возможность определять еще два других типа макросов: "атрибутные процедурные макросы" и "функциональные процедурные макросы".
Атрибутные макросы подобны 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
Теперь можно импортировать макросы в область видимости с помощью ключевого слова use [5]. Например, для использования макроса json
из пакета serde-json
, раньше использовалась запись:
#[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
.
Наконец, стабилизирован пакет proc_macro [6], который дает API, необходимый для написания процедурных макросов. В нем также значительно улучшили API для обработки ошибок, и такие пакеты, как syn
и quote
уже используют его. Например, раньше:
#[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'е; некоторые из ее правил оказывались неудобными на практике. Настоящие изменения являются первым шагом, который мы предпринимаем на пути упрощения системы модулей.
В дополнении к вышеупомянутому изменению для макросов, есть два новых улучшения в использовании use
. Во-первых, внешние пакеты теперь добавляются в prelude [7], то есть:
// было
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 [7]:
mod foo {
pub fn bar() {
// ...
}
}
// было
use ::foo::bar;
// или
use foo::bar;
// стало
use crate::foo::bar;
Ключевое слово crate
в начале пути указывает, что путь будет начинаться от корня пакета. Раньше пути, указанные в строке импорта use
, всегда указывались относительно корня пакета, но пути в остальном коде, напрямую ссылающиеся на элементы, указывались относительно текущего модуля, что приводило к противоречивому поведению путей:
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
, всегда начинающихся от корня пакета, по-прежнему применимо. Но при единовременном переходе на новый стиль, данные правила будут применяться к путям повсюду единообразно, и вам придется гораздо меньше заботиться об импортах при перемещении кода.
Вы можете теперь использовать ключевые слова как идентификаторы [8], используя следующий новый синтаксис:
// определение локальной переменной с именем `for`
let r#for = true;
// определение функции с именем `for`
fn r#for() {
// ...
}
// вызов той функции
r#for();
Пока не так много случаев, когда вам это пригодится. Но однажды вы попытаетесь использовать пакет для Rust 2015 в проекте для Rust 2018 или наоборот, тогда набор ключевых слов у них будет разным. Мы расскажем об этом подробнее в предстоящем анонсе Rust 2018.
Еще в Rust 1.6 мы объявили о стабилизации "no_std" и libcore [9] для создания проектов без стандартной библиотеки. Однако, с одним уточнением: можно было создавать только библиотеки, но не приложения.
В Rust 1.30 можно использовать атрибут #[panic_handler]
[10] для самостоятельной реализации паники. Это означает, что теперь можно создавать приложения, а не только библиотеки, которые не используют стандартную библиотеку.
И последнее: в макросах теперь можно сопоставлять модификаторы области видимости [11], такие как pub
, с помощью спецификатора vis
. Дополнительно, "инструментальные атрибуты", такие как #[rustfmt::skip]
, теперь стабилизированы [12]. Правда для использования с инструментами статического анализа, наподобие #[allow(clippy::something)]
, они еще не стабильны.
Подробности смотрите в примечаниях к выпуску [2].
В этом выпуске были стабилизированы следующие API [13]:
Ipv4Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}
Ipv6Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}
Iterator::find_map
Кроме того, стандартная библиотека уже давно имеет функции для удаления пробелов с одной стороны некоторого текста, такие как trim_left
. Однако, для RTL-языков значение "справа" и "слева" тут приводят к путанице. Поэтому мы вводим новые имена для этих функций:
trim_left
-> trim_start
trim_right
-> trim_end
trim_left_matches
-> trim_start_matches
trim_right_matches
-> trim_end_matches
Мы планируем объявить устаревшими старые имена (но не удалить, конечно) в Rust 1.33.
Подробности смотрите в примечаниях к выпуску [2].
Самое большое улучшение Cargo в этом выпуске заключается в том, что теперь у нас есть индикатор выполнения! [14]
Подробности смотрите в примечаниях к выпуску [2].
Множество людей совместно создавало Rust 1.30. Мы не смогли бы завершить работу без участия каждого из вас. Спасибо! [15]
От переводчика: выражаю отдельную благодарность участникам сообщества Rustycrate и лично vitvakatu [16] и Virtuos86 [17] за помощь с переводом и вычиткой.
Автор: freecoder_xx
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/297335
Ссылки в тексте:
[1] установить его: https://www.rust-lang.org/install.html
[2] подробными примечаниями к выпуску Rust 1.30.0: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1300-2018-10-25
[3] "What is Rust 2018": https://blog.rust-lang.org/2018/07/27/what-is-rust-2018.html
[4] Rust 1.15: https://blog.rust-lang.org/2017/02/02/Rust-1.15.html
[5] импортировать макросы в область видимости с помощью ключевого слова use: https://github.com/rust-lang/rust/pull/50911/
[6] пакет proc_macro: https://doc.rust-lang.org/stable/proc_macro/
[7] внешние пакеты теперь добавляются в prelude: https://github.com/rust-lang/rust/pull/54404/
[8] Вы можете теперь использовать ключевые слова как идентификаторы: https://github.com/rust-lang/rust/pull/53236/
[9] стабилизации "no_std" и libcore: https://blog.rust-lang.org/2016/01/21/Rust-1.6.html
[10] #[panic_handler]
: https://github.com/rust-lang/rust/pull/51366/
[11] сопоставлять модификаторы области видимости: https://github.com/rust-lang/rust/pull/53370/
[12] теперь стабилизированы: https://github.com/rust-lang/rust/pull/53459/
[13] стабилизированы следующие API: https://github.com/rust-lang/rust/blob/master/RELEASES.md#stabilized-apis
[14] у нас есть индикатор выполнения!: https://github.com/rust-lang/cargo/pull/5995/
[15] Спасибо!: https://thanks.rust-lang.org/rust/1.30.0
[16] vitvakatu: https://habr.com/users/vitvakatu/
[17] Virtuos86: https://habr.com/users/virtuos86/
[18] Источник: https://habr.com/post/428073/?utm_campaign=428073
Нажмите здесь для печати.