LINUX.ORG.RU

Rust 1.31.0 (2018)

 , rust2018


5

10

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

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

rustup update stable

Если у вас ещё не установлен Rust, то это можно сделать, загрузив с сайта утилиту rustup.

Что нового в Rust 1.31.0

Rust 2018

Данный релиз ознаменует собой выпуск редакции Rust 2018. Впервые Rust 2018 был упомянут в марте, затем в июле: прочтите их, чтобы понимать для чего нужен Rust 2018. Также, есть статья на сайте Mozilla Hacks.

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

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

Для обозначения редакций Rust был представлен ключ edition в Cargo.toml:

[package]
name = "foo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"

[dependencies]

Значение 2018 означает, что используется редакция Rust 2018; отсутствие ключа или значение 2015 означает использование редакции Rust 2015.

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

Non-lexical lifetimes (NLL; Нелексические времена жизни)

В 2018 появились нелексические времена жизни, что на простом языке означает, что проверщик заимствований (borrow checker) стал умнее и теперь не отклоняет правильный код. Например:

fn main() {
    let mut x = 5;

    let y = &x;

    let z = &mut x;
}

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

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
6 | }
  | - immutable borrow ends here

из-за того, что время жизни действует внутри лексического блока; то есть, заимствование будет удерживаться за y, пока y не покинет пределы main, несмотря на то, что 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 2018, но в будущем планируется портировать их на Rust 2015.

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

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

Вкратце:

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

Полную информацию можно прочесть в руководстве.

Упрощенные правила синтаксиса времени жизни

В обеих редакциях представлены новые правила синтаксиса времени жизни для блоков impl и определениях функций. Следующий код:

impl<'a> Reader for BufReader<'a> {
    // methods go here
}
теперь может быть написан таким образом:
impl Reader for BufReader<'_> {
    // methods go here
}

'_ подсказывает, что 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 fn могут вызываться как регулярные функции, но вычисляются во время компиляции, а не во время выполнения. Для стабильной работы, они должны иметь детерминированный результат и в настоящее время ограничены следующим минимальным набором операций:

  • Арифметические операторы и операторы сравнения с целыми числами
  • Все логические операторы, кроме && и ||
  • Построение массивов, структур, перечислений и кортежей
  • Вызов других функций const fn
  • Задание индекса массивам и срезам
  • Доступ к полям структур и кортежей
  • Чтение из констант
  • & и * на ссылках
  • Приведение типов, за исключением необработанных указателей на целые числа

В будущем данный набор будет расширяться, подробную информацию можно посмотреть здесь.

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

Наряду с Cargo, Rustdoc, и Rustup, которые являются ключевыми инструментами с версии 1.0, редакция 2018 представляет новое поколение инструментов: Clippy, Rustfmt, и поддержку IDE.

Clippy является статическим анализатором кода в Rust, достиг версии 1.0 и теперь доступен в стабильной версии Rust. Установку можно произвести следующим образом: rustup component add clippy, запуск: cargo clippy.

Rustfmt является инструментом для автоматического форматирования кода Rust в соответствии с официальной стилистикой Rust. В этом релизе он достиг версии 1.0 и, начиная с этой версии, гарантируется обратная совместимость для Rustfmt: отформатированный сегодня код останется неизменным в будущем (только с опциями использованными по-умолчанию), и несёт практическую ценность при использовании с системами непрерывной интеграции (CI; cargo fmt --check). Установить Rustfmt можно следующим образом: rustup component add rustfmt, использовать: cargo fmt.

Поддержка IDE - одна из наиболее востребованных возможностей в Rust. Работы над поддержкой IDE ещё не закончены, но на данный момент уже существуют несколько высококачественных опций:

Tool lints

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

// old
#![cfg_attr(clippy, bool_comparison)]

// new
#![allow(clippy::bool_comparison)]

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

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

Рабочие группы

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

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

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

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

Новый сайт

Основной сайт получил новый дизайн.

Стабилизация библиотек

Добавлено множество реализаций From:

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

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

  • slice::align_to и её изменяемый аналог
  • slice::chunks_exact и её изменяемый и r аналоги (такие как slice::rchunks_exact_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.

Подробный список изменений можно посмотреть здесь.

>>> Подробности

★★★★★

Проверено: Shaman007 ()
Последнее исправление: Deleted (всего исправлений: 5)

Ответ на: комментарий от Deleted

Делаешь свои трейты / Перегружаешь операторы

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

Deleted
()
Ответ на: комментарий от Deleted

Да, но типичные (А так же повторяющиеся) операции принято оборачивать в какую-нибудь функцию или трейт.

Deleted
()
Ответ на: комментарий от Deleted

И что тут неудобного?

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

use std::collections::BTreeSet;

#[derive(Debug, Deserialize, Serialize)]
struct Location {
    latitude: f64,
    longtitude: f64,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")]
enum Meal {
    Breakfast,
    Lunch,
    Dinner,
}

#[derive(Debug, Deserialize, Serialize)]
struct Restaurant {
    name: String,
    location: Location,
    meals: BTreeSet<Meal>,
}

fn main() {
    // Serialization
    let restaurant = Restaurant {
        name: "A Restaurant".to_owned(),
        location: Location {
            longtitude: 10.1,
            latitude: 20.2,
        },
        meals: [Meal::Breakfast, Meal::Dinner, Meal::Lunch]
            .iter()
            .cloned()
            .collect(),
    };

    let restaurant_json = serde_json::to_string_pretty(&restaurant).unwrap();

    println!("{}\n", restaurant_json);

    // Deserialization
    let restaurant: Restaurant = serde_json::from_str(&restaurant_json).unwrap();

    print!("{:?}", restaurant);
}
{
  "name": "A Restaurant",
  "location": {
    "latitude": 20.2,
    "longtitude": 10.1
  },
  "meals": [
    "breakfast",
    "lunch",
    "dinner"
  ]
}

Restaurant { name: "A Restaurant", location: Location { latitude: 20.2, longtitude: 10.1 }, meals: {Breakfast, Lunch, Dinner} }

Deleted
()
Ответ на: комментарий от mersinvald

Я сейчас именно на нем и делаю. И буду продолжать, пока раст не дозреет.

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

Vit ★★★★★
()
Ответ на: комментарий от Deleted

Я и не пытался. Это аналогия с тем что по ссылке про Swift. _ИМО_, вариант на ржавчине выглядит значительно проще и короче.
Но если есть жизненный пример JSON-а и хорошая, годная реализация работы с ним не на Rust - внесите в студию!

Deleted
()
Ответ на: комментарий от Freyr69

Создают тестовую прграмму на каждый чих?

Да, именно так. И делать это надо регулярно, для каждого сложного класса, а не когда уже деваться некуда.

Если у меня 666 объектов и где-то утечка, я все разом целиком валграйнду не смогу скормить.

Спасибо, кэп.

hobbit ★★★★★
()
Ответ на: комментарий от Partisan

начинает считать авторов языка дураками

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

dinama
()
Ответ на: комментарий от quantum-troll

Эти ключевые слова значительно упрощают синтаксический разбор, чтобы не было как в С++.

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

Очевидное вредительство. Неизменяемые привязки встречаются куда чаще, и в отличие от const, mut нельзя забыть — так что язык способствует правильному использованию изменяемости.

чепуха. это была фича ради фичи. ну и да - const и mut в одной банки это сигнал об ошибке проектирования.

Хорошо разработанный язык способствует хорошим практикам, а не антипаттернам.


хорошо обученный демагог излагает клише, но не мысли

Регистр указывает чем является конкретное имя — переменной, типом или константой.


кому указывает? он ни на что не указывает, кроме того, что у проектировщиков баги в голове. во всяких Qt, MFC и прочих хоть догадались какую-то букву в начае вставлять, что-бы не создавать мещанину с объектами предметной области.

dinama
()
Ответ на: комментарий от dinama

недавно была статья где один из авторов считает что mut лишнее.

Ссылку?

зачем const если есть mut

В учебника это объясняют.

работу надо облегчать программисту, а не синтаксическому анализатору

Под этим девизом сделали Си++.

кому указывает? он ни на что не указывает

Мне указывает. А кому не указывает?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 2)
Ответ на: комментарий от tailgunner

В учебника это объясняют.


объяснить можно что угодно десятком способов. толку-то.

Под этим девизом сделали Си++.

c++ очень легкий язык. я бы сказал, что самый легкий из всех. легче только C.

dinama
()
Ответ на: комментарий от dinama

объяснить можно что угодно десятком способов

Ты эту претензию и к другим языкам относишь?

Под этим девизом сделали Си++.

c++ очень легкий язык

Просто ты не знаешь Си++.

tailgunner ★★★★★
()
Ответ на: комментарий от dave

а ты похоже, что действительно не знаком с языком.

это не язык, а стандартная библиотека. и да - разумеется я с ней не знаком.
уже 100 раз бы перешел на rust, если бы не вот это блевота
с let, fn и заглавными буквами в стандартной либе.

dinama
()
Ответ на: комментарий от dinama

c++ очень легкий язык

Просто ты не знаешь Си++.

просто ты очень толстый.

Не я.

tailgunner ★★★★★
()
Ответ на: комментарий от dinama

100 раз бы перешел на rust, если бы не вот это блевота с let, fn и заглавными буквами в стандартной либе

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

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 1)
Ответ на: комментарий от mersinvald

Я нуб в расте, но задерайвив Copy для Meal и убрав .cloned() получаю ошибку

a collection of type `std::collections::BTreeSet<Meal>` cannot be built from `std::iter::Iterator<Item=&Meal>`

ЧЯДНТ?

nemec784
()
Ответ на: комментарий от dinama

Ты болен. Зачем ты запихиваешь умный указатель в умный указатель?
- dearAmomynous

anonymous
()
Ответ на: комментарий от nemec784

Ну да, мой косяк. Тогда нужно разыменование дополнительно, лучше cloned оставить (альтернатива .map(|&t| t), что не очень интуитивно). Но Copy однозначно дерайвить стоит.

mersinvald ★★★★★
()
Последнее исправление: mersinvald (всего исправлений: 1)
Ответ на: комментарий от nemec784

cloned() там всё-таки нужен. Для массивов нет поглощающих итераторов. С вектором бы это сработало. Впрочем, сработало бы и без Copy.

meals: vec![Meal::Breakfast, Meal::Dinner, Meal::Lunch]
            .into_iter()
            .collect()
red75prim ★★★
()
Ответ на: комментарий от red75prim

Ну на ровном месте память выделять некомильфо.

mersinvald ★★★★★
()
Ответ на: комментарий от mersinvald

Это же просто пример - всё по минимуму, лишь бы работало. Так то там не только Copy стоит задерайвить.

Deleted
()
Ответ на: комментарий от red75prim

Для массивов нет поглощающих итераторов.

Это, кстати, очень печально. Как сделают const-dependent generics - заживём.

Deleted
()
Ответ на: комментарий от tailgunner

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

anonymous
()
Ответ на: комментарий от dinama

с let, fn и заглавными буквами в стандартной либе

А чем let не угодил? Вполне себе удобный оператор сопоставления и ввода новых имен.

freecoder
()
Ответ на: комментарий от Deleted

Что ж тут смешного)

hash
    .entry("porn".into())
    .or_insert("100Gb".into());

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

Virtuos86 ★★★★★
()
Ответ на: комментарий от Deleted

«Не нраицца» это и есть мое возражение)

А вы, простите, кто, чтобы обращать внимание на ваше субъективное мнение?

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Гражданин Российской Федерации! Паспорт показать?

Я понимаю, язык для системных програмистов и байтолюбство проблем не вызовет. Но если кому-то придет в голову заюзать руст для веба, эти into() ему потом снится будут

Deleted
()
Ответ на: комментарий от Virtuos86

Да. Но сравнение уместно. Кто-то не захотел делать сахарок и теперь над ними будут потешаться до конца дней

Deleted
()
Ответ на: комментарий от Deleted

Да. Но сравнение уместно. Кто-то не захотел делать сахарок и теперь малолетние ололоши над ними будут потешаться до конца дней

Ну что ж, детям это простительно, подрастут, повзрослеют, наберутся ума-разума, самим стыдно станет.

Virtuos86 ★★★★★
()
Ответ на: комментарий от Deleted

Я понимаю, язык для системных програмистов и байтолюбство проблем не вызовет. Но если кому-то придет в голову заюзать руст для веба, эти into() ему потом снится будут

Тогда, верно, Сеть должна быть усыпана плачами Ярославны от искалеченных into программистами. Давай, накидай ссылок на вселенскую боль кодеров на Rust от необходимости конвертации строковых срезов в строки и обратно.

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

О. И последователи Go такого же мнения. Говорят, что if err != nil { return nil, err } это чистый и прозрачный способ проброса ошибки и вообще огромный шаг вперед в теории ЯП. А те кто ржет с этого — не разобравшиеся дебилы

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.