Pull to refresh

Выпуск Rust 1.40.0: #[non_exhaustive], усовершенствования макросов и прочие улучшения

Reading time 5 min
Views 5.5K
Original author: The Rust Release Team

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


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


$ rustup update stable

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


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


Основными новшествами являются введение атрибута #[non_exhaustive], улучшения macros!() и #[attribute]. Наконец, миграционные предупреждения анализатора заимствований стали ошибками в Rust 2015. Смотрите подробности выпуска для дополнительной информации.


#[non_exhaustive] структуры, перечисления и варианты перечислений


Предположим, вы являетесь автором библиотеки alpha, которая содержит pub struct Foo. Вы хотели бы сделать поля структуры alpha::Foo публичными, но не уверены, придётся ли вам в будущих выпусках добавить больше полей в Foo. Возникает дилемма: либо вы делаете поля приватными с последующими неудобствами, либо вы рискуете поставить пользователей в зависимость от полей и потом нарушит их код при добавлении новых. В Rust 1.40.0 представлен способ решить проблему с помощью #[non_exhaustive].


Атрибут #[non_exhaustive] прикрепляется к структуре или варианту перечисления и препятствует полному сопоставлению полей, созданию упомянутой структуры или варианта вне крейта с их объявлением. Следующий пример демонстрирует ошибки в крейте beta, зависящего от alpha:


// alpha/lib.rs:

#[non_exhaustive]
struct Foo {
    pub a: bool,
}

enum Bar {
    #[non_exhaustive]
    Variant { b: u8 }
}

fn make_foo() -> Foo { ... }
fn make_bar() -> Bar { ... }

// beta/lib.rs:

let x = Foo { a: true }; //~ ОШИБКА
let Foo { a } = make_foo(); //~ ОШИБКА
let Foo { a, .. } = make_foo(); //~ OK
          // -- `beta` все еще будет компилироваться при добавлении полей.

let x = Bar::Variant { a: 42 }; //~ ОШИБКА
let Bar::Variant { b } = make_bar(); //~ ОШИБКА
let Bar::Variant { b, .. } = make_bar(); //~ OK
                   // -- `beta` все еще будет компилироваться...

Что же происходит за кулисами? Видимость конструкторов для #[non_exhaustive] структуры или варианта перечисления будет понижена до pub(crate), тем самым запрещая их использование в сторонних крейтах.


Возможно, что более важным аспектом #[non_exhaustive] является то, что атрибут может быть прикреплён к самим перечислениям. Вот код, взятый из std::cmp::Ordering:


#[non_exhaustive]
pub enum Ordering { Relaxed, Release, Acquire, AcqRel, SeqCst }

В данном случае #[non_exhaustive] гарантирует возможность добавления новых вариантов в будущем. Это достигается запретом другим пакетам к использованию исчерпывающего сопоставления с образом для Ordering. Компилятор бы отклонил следующее:


match ordering {
    Relaxed | Release | Acquire | AcqRel | SeqCst => { /* logic */ }
    //~^ ОШИБКА; если новый вариант был бы добавлен,
    // это сломалось бы, если ошибки не было бы с самого начала.
}

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


match ordering {
    Relaxed | Release | Acquire | AcqRel | SeqCst => { /* logic */ }
    _ => { /* logic */ } // OK; если будут добавлены новые варианты, ничего не сломается.
}

Подробная информация об атрибуте #[non_exhaustive] доступна в отчёте о стабилизации.


Улучшения макросов и атрибутов


В 1.40.0 мы внесли несколько улучшений в макросы и атрибуты, включая:



Миграционные предупреждения анализатора заимствований становятся ошибками в редакции Rust 2015


В выпуске 1.35.0 мы сообщили, что NLL появился в редакции Rust 2015 после первого выпуска для 2018 редакции в Rust 1.31.


Как мы сказали, старый анализатор заимствований мог допустить небезопасное управление памятью, и с помощью нового анализатора (NLL borrow checker) эти недочёты были решены. Так как эти ошибки могли нарушить работу стабильного кода, мы решили постепенно вводить эти ошибки, проверяя разрешит ли сборку программы старый анализатор, и запретит ли её новый. В этих случаях ошибки заменялись предупреждениями.


Предыдущий выпуск Rust 1.39.0 заменил эти предупреждения на ошибки для кода с 2018 редакцией. Rust 1.40.0 применит те же самые изменения для кода 2015 редакции, навсегда закрывая эти дыры в безопасности. Вместе с этим компилятор даже почистили от старого кода!


Если ваш проект не собирается из-за вышеописанных изменений, или вы хотите узнать больше, читайте пост Niko Matsakis's.


Больше константных функций в стандартной библиотеке


Начиная с Rust 1.40.0, следующая функция помечена как константная (const fn):



Стабилизированные функции в стандартной библиотеке


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



Другие изменения


Синтаксис, пакетный менеджер Cargo и анализатор Clippy также претерпели некоторые изменения.


Пожалуйста, прочтите заметки о совместимости, чтобы узнать, затронут ли вас эти изменения.


Участники 1.40.0


Множество людей собрались вместе, чтобы создать Rust 1.40.0. Мы не смогли бы сделать это без всех вас, спасибо!


От переводчиков


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


Данную статью совместными усилиями перевели andreevlex, blandger, funkill, Hippolot, P0lunin, PsyHaSTe и LooMaclin.

Tags:
Hubs:
+49
Comments 58
Comments Comments 58

Articles