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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Команда 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 мы внесли несколько улучшений в макросы и атрибуты, включая:


  • Вызов процедурных макросов mac!() в контекстах типов.


    Например, можно написать type Foo = expand_to_type!(bar); где expand_to_type будет процедурным макросом.


  • Макросы в extern { ... } блоках.


    Этот блок включает макросы make_item!(). Например:


    macro_rules! make_item { ($name:ident) => { fn $name(); } }
    
    extern {
        make_item!(alpha);
        make_item!(beta);
    }

    Атрибутные процедурные макросы для элементов в extern { ... } блоках теперь также поддерживаются:


    extern "C" {
        #[my_identity_macro] //~ Давайте предположим, что это расширяется до `fn foo();`.
        fn foo();
    }

  • Генерация macro_rules! элементов в процедурных макросах.


    Макросы с синтаксисом функций (mac!()) и атрибуты (#[mac]) теперь могут генерировать элементы macro_rules!. Подробнее смотрите в прилагаемом отчёте о стабилизации.


  • Теперь сопоставление с помощью $m:meta поддерживает произвольные значения TokenStream.


    То есть следующий код является корректным:


    macro_rules! accept_meta { ($m:meta) => {} }
    accept_meta!( my::path );
    accept_meta!( my::path = "lit" );
    accept_meta!( my::path ( a b c ) );
    accept_meta!( my::path [ a b c ] );
    accept_meta!( my::path { a b c } );


Миграционные предупреждения анализатора заимствований становятся ошибками в редакции 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):


  • is_power_of_two для беззнаковых целых чисел

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


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


  • todo!()


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


  • slice::repeat


    Создаёт Vec<T> из 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<Box<T>>, создают Option<&T> и Option<&mut T> соответственно.


  • Option::flatten


    Эта функция, подобно Iterator::flatten, разворачивает Option<Option<T>> в Option<T>, производя 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.

Источник: https://habr.com/ru/post/481070/


Интересные статьи

Интересные статьи

Много всякого сыпется в мой ящик, в том числе и от Битрикса (справедливости ради стоит отметить, что я когда-то регистрировался на их сайте). Но вот мне надоели эти письма и я решил отписатьс...
В 1С-Битрикс: Управление сайтом (как и в Битрикс24) десятки, если не сотни настраиваемых типов данных (или сущностей): инфоблоки, пользователи, заказы, склады, форумы, блоги и т.д. Стр...
История сегодня пойдёт про автосервис в Москве и его продвижении в течении 8 месяцев. Первое знакомство было ещё пару лет назад при странных обстоятельствах. Пришёл автосервис за заявками,...
Существует традиция, долго и дорого разрабатывать интернет-магазин. :-) Лакировать все детали, придумывать, внедрять и полировать «фишечки» и делать это все до открытия магазина.
Представляю вашему вниманию перевод публикации о новой версии всеми любимого языка программирования Rust. Введение Команда по разработке языка программирования Rust рада анонсировать новую верс...