Выпуск Rust 1.37.0: Profile-Guided Optimization, неименованные константы и cargo vendor

в 15:00, , рубрики: cargo, clippy, open source, release, Rust, rustc, rustdoc, rustfix, rustfmt, stable, выпуск версий, новости технологий, перевод, системное программирование, стабильная версия, языки программирования

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

Введение

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

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

$ rustup update stable

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

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

Основные новшества в Rust 1.37.0 включают в себя ссылки на варианты перечисления (enum) через псевдонимы типов (type), встроенный cargo vendor, неименованные константы (const), profile-guided optimization, ключ default-run для Cargo проектов и #[repr(align(N))] для перечислений. Для получения дополнительной информации ознакомьтесь с подробными примечаниями к выпуску.

Ссылки на варианты перечисления (enum) через псевдонимы типов (type)

Начиная с Rust 1.37.0, ссылаться на варианты перечисления (enum) стало возможным через псевдонимы типов:

type ByteOption = Option<u8>;

fn increment_or_zero(x: ByteOption) -> u8 {
    match x {
        ByteOption::Some(y) => y + 1,
        ByteOption::None => 0,
    }
}

В impl блоках Self выступает в качестве псевдонима типа, поэтому в Rust 1.37.0 стало возможным ссылаться на варианты перечисления, используя синтаксическую конструкцию Self::Variant:

impl Coin {
    fn value_in_cents(&self) -> u8 {
        match self {
            Self::Penny => 1,
            Self::Nickel => 5,
            Self::Dime => 10,
            Self::Quarter => 25,
        }
    }
}

А точнее, теперь Rust позволяет ссылаться на варианты перечисления через "type-relative resolution", <MyType<..>>::Variant. Более подробное описание доступно в отчёте о стабилизации.

Встроенная поддержка Cargo для зависимостей поставщика

После нескольких лет существования в качестве отдельного пакета, команда cargo vendor теперь интегрирована в Cargo. Данная команда извлекает все зависимости вашего проекта в каталог vendor/ и показывает фрагмент конфигурации, необходимый для использования кода поставщика во время сборки.

cargo vendor уже применяется в реальных проектах: компилятор Rust rustc использует его для отправки всех своих зависимостей в tar-архивы выпусков, а проекты с монорепозиториями используют его для фиксации кода зависимостей в системе управления версиями.

Использование неименованных констант (const) в макросах

Теперь вы можете создавать неименованную (unnamed) константу (const), подменив её идентификатор нижним подчёркиванием (_). Например, в компиляторе rustc мы нашли такой код:

/// Проверка размера типа, где первый параметр
/// это тип, а второй - ожидаемый размер.
#[macro_export]
macro_rules! static_assert_size {
    ($ty:ty, $size:expr) => {
        const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
        //    ^ Обратите внимание на подчеркивание.
    }
}

static_assert_size!(Option<Box<String>>, 8); // 1.
static_assert_size!(usize, 8); // 2.

Обратите внимание на второй static_assert_size!(..): благодаря использованию неименованных констант стало возможным предотвратить конфликт имён при объявлении новых элементов. Ранее вам нужно было бы написать static_assert_size!(MY_DUMMY_IDENTIFIER, usize, 8);. С введением неименованных констант становится проще создавать эргономичные и многократно используемые декларативные и процедурные макросы для целей статического анализа.

Profile-guided optimization

В компиляторе rustc теперь доступна Profile-Guided Optimization (PGO), которую можно включить через флаги компилятора -C profile-generate и -C profile-use.

Profile-Guided Optimization — это техника оптимизации программ компиляторами, анализирующая тестовые запуски, вместо исходного кода. Она работает путём компиляции программы для оптимизации в два этапа:

  1. Сперва программа создаётся средствами инструментария, встроенного в компилятор. Это делается путём передачи rustc флага -C profile-generate. Затем инструментальная программа должна быть запущена на образцах данных и впоследствии она запишет в файл данные профилирования.
  2. Затем программа снова собирается, на этот раз подавая собранные данные профилирования обратно в rustc с помощью флага -C profile-use. Эта сборка будет использовать собранные данные, чтобы позволить компилятору принимать лучшие решения о размещении кода, встраивании и других оптимизациях.

Для получения более подробной информации о Profile-Guided Optimization смотрите соответствующую главу в книге по компилятору rustc.

Выбор исполняемого файла в Cargo проектах

cargo run является весьма удобным инструментом для быстрого тестирования консольных приложений. Когда в одном пакете присутствует несколько исполняемых файлов, необходимо явно объявить имя того исполняемого файла, который вы хотите запустить при помощи флага --bin. Это делает cargo run не таким эргономичным, как хотелось бы, особенно когда определённый исполняемый файл вызывается чаще, чем другие.

Rust 1.37.0 решает данную проблему путём добавления нового ключа default-run в Cargo.toml (секция [package]). Таким образом, при необнаружении флага --bin, Cargo запустит двоичный файл, объявленный в конфигурации.

#[repr(align(N))] для перечислений

Начиная с Rust 1.37.0, атрибут #[repr(align(N))] может быть использован для определения выравнивания перечислений в памяти (ранее данный атрибут был разрешён только для структур (struct) и объединений (union)). Например, перечисление Align16 будет, как и ожидалось, иметь выравнивание в 16 байт, тогда как естественное выравнивание без #[repr(align(16))] будет 4:

#[repr(align(16))]
enum Align16 {
    Foo { foo: u32 },
    Bar { bar: u32 },
}

Семантика использования #[repr(align(N)) для перечислений такая же, как определение обёртки для структуры AlignN<T> с этим выравниванием, а затем использование AlignN<MyEnum>:

#[repr(align(N))]
struct AlignN<T>(T);

Изменения в стандартной библиотеке

Rust 1.37.0 стабилизировал следующие компоненты стандартной библиотеки:

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

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

Участники 1.37.0

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

Новые спонсоры инфраструктуры Rust

Мы хотели бы поблагодарить двух новых спонсоров инфраструктуры Rust, предоставивших ресурсы, необходимых для создания Rust 1.37.0: Amazon Web Services (AWS) and Microsoft Azure:

  • AWS предоставили хостинг для артефактов выпуска (компиляторы, библиотеки, инструменты и исходный код), дали доступ до этих артефактов пользователям через CloudFront, предотвратили регрессии на EC2 с Crater и управляли другой инфраструктурой, связанной с Rust, размещённой на AWS.
  • Для чрезвычайно ресурсоёмкого тестирования репозитория rust-lang/rust Microsoft Azure предоставила сборщики.

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

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

Данную статью совместными усилиями перевели andreevlex, ozkriff, funkill и Gymmasssorla.

Автор: Gymmasssorla

Источник


* - обязательные к заполнению поля