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

?v=1

Команда 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 были стабилизированы следующие функции и макросы:


  • todo!()

    Более короткая, запоминающаяся и удобная версия макроса [unimplemented!()].


  • slice::repeat

    Создаёт Vec из n повторений среза.


  • mem::take

    Эта функция забирает значения из изменяемой ссылки и заменяет их значением по умолчанию для данного типа. Она похожа на Option::take и Cell::take и является удобным сокращением для mem::replace(&mut dst, Default::default()).


  • BTreeMap::get_key_value и HashMap::get_key_value

    Возвращает пару ключ-значение, соответствующие предоставленному ключу.


  • Option::as_deref, Option::as_deref_mut

    Они работают подобно Option::as_ref и Option::as_mut, но используют Deref и DerefMut соответственно, таким образом, opt_box.as_deref() и opt_box.as_deref_mut(), где opt_box: Option>, создают Option<&T> и Option<&mut T> соответственно.


  • Option::flatten

    Эта функция, подобно Iterator::flatten, разворачивает Option> в Option, производя Some(x) для Some(Some(x)) и None в противном случае.


  • UdpSocket::peer_addr

    Возвращает адрес удалённого узла, к которому подключён сокет.


  • {f32,f64}::to_be_bytes, {f32,f64}::to_le_bytes, {f32,f64}::to_ne_bytes, {f32,f64}::from_be_bytes, {f32,f64}::from_le_bytes и {f32,f64}::from_ne_bytes

    Возвращают представление в памяти числа с плавающей точкой в виде массива байт с big-endian (network), little-endian или native-endian порядком байт.



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

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

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


Участники 1.40.0

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


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

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

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

© Habrahabr.ru