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


[политическое сообщение удалено из-за правил Хабра]


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

rustup update stable

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

Что стабилизировано в 1.59.0

Встроенный ассемблер

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

Например, при компиляции под x86-64 вы теперь можете написать:

use std::arch::asm;

// Умножить x на 6 с помощью сдвигов и сложений
let mut x: u64 = 4;
unsafe {
    asm!(
        "mov {tmp}, {x}",
        "shl {tmp}, 1",
        "shl {x}, 2",
        "add {x}, {tmp}",
        x = inout(reg) x,
        tmp = out(reg) _,
    );
}
assert_eq!(x, 4 * 6);

Синтаксис форматирования строки, используемый для именования регистров в макросах asm! и global_asm!, используется в обычном форматировании строк Rust, поэтому он должен быть знакомым Rust-программистам.

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

  • x86 и x86-64

  • ARM

  • AArch64

  • RISC-V

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

Деструктурирующее присваивание

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

let (a, b, c, d, e);

(a, b) = (1, 2);
[c, .., d, _] = [1, 2, 3, 4, 5];
Struct { e, .. } = Struct { e: 5, f: 3 };

assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);

Это делает присваивания более согласованными с привязками let, которые уже давно поддерживают это. Обратите внимание, что деструктурирующее присваивание не разрешено в таких операторах, как +=.

Значения по умолчанию для константных обобщений и чередования

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

struct ArrayStorage<T, const N: usize = 2> {
    arr: [T; N],
}

impl<T> ArrayStorage<T> {
    fn new(a: T, b: T) -> ArrayStorage<T> {
        ArrayStorage {
            arr: [a, b],
        }
    }
}

Ранее параметры типа требовалось писать до всех константных параметров. Это ограничение было ослаблено, и теперь вы можете чередовать их.

fn cartesian_product<
    T, const N: usize,
    U, const M: usize,
    V, F
>(a: [T; N], b: [U; M]) -> [[V; N]; M]
where
    F: FnMut(&T, &U) -> V
{
    // ...
}

Предупреждения о будущей несовместимости

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

Хотя это случается очень редко, такое поведение может быть весьма разрушительным – когда в крейте, используемом вашим проектом, есть код, который больше не будет разрешён. Вы этого можете даже не заметить, пока ваш проект необъяснимым образом не перестанет собираться!

Cargo теперь показывает вам предупреждения, когда зависимость будет отклонена будущей версией Rust. После запуска cargo build или cargo check вы сможете увидеть:

warning: the following packages contain code that will be rejected by a future version of Rust: old_dep v0.1.0
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`

Вы можете запустить команду cargo report, упомянутую в предупреждении, чтобы увидеть полный отчёт о коде, который будет отклонён. Это даёт вам время обновить вашу зависимость, прежде чем она сломает всю сборку.

Создание урезанных бинарных файлов

Часто вырезание информации, например отладочной, из поставляемых вами бинарных файлов, уменьшает их размер.

Это можно сделать вручную в любой момент после создания бинарного файла, но теперь cargo и rustc поддерживают урезание на этапе линковки. Для включения данной функциональности добавьте в Cargo.toml следующее:

[profile.release]
strip = "debuginfo"

Это приведёт к вырезанию отладочной информации из релизных сборок. Вы также можете поставить "symbols" или просто true чтобы вырезать всю информацию о символах, которая возможна.

Стандартная библиотека обычно поставляется с отладочными символами и отладочной информацией, так что бинарные файлы Rust, собираемые без отладочной информации, по умолчанию включают в себя информацию об отладке стандартной библиотеки. Использование опции strip позволяет вам удалить эту дополнительную информацию, чтобы создать более компактные бинарные файлы.

Для большей информации смотрите документацию Cargo.

Инкрементальная компиляция отключена по умолчанию

Версия 1.59.0 по умолчанию отключает инкрементный режим (если его явно не запросить через переменную среды RUSTC_FORCE_INCREMENTAL=1). Это смягчает последствия известной ошибки #94124, которая может вызывать ошибки десериализации (и панику) во время компиляции с включённой инкрементной компиляцией.

Специальное исправление для #94124 появилось и в настоящее время находится в бета-версии 1.60, которая будет выпущена через шесть недель. В настоящее время мы не знаем о других проблемах, которые побудили бы принять решение об отключении инкрементной компиляции в стабильной версии 1.60, и если они не возникнут, вполне вероятно, что в стабильной версии 1.60 снова будет включена инкрементная компиляция. Инкрементная компиляция остаётся включённой по умолчанию в бета-версии и ночных каналах.

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

Стабилизированные API

Стабилизированы следующие методы и реализации трейтов:

  • std::thread::available_parallelism

  • Result::copied

  • Result::cloned

  • arch::asm!

  • arch::global_asm!

  • ops::ControlFlow::is_break

  • ops::ControlFlow::is_continue

  • TryFrom<char> для u8

  • char::TryFromCharError реализующие Clone, Debug, Display, PartialEq, Copy, Eq, Error

  • iter::zip

  • NonZeroU8::is_power_of_two

  • NonZeroU16::is_power_of_two

  • NonZeroU32::is_power_of_two

  • NonZeroU64::is_power_of_two

  • NonZeroU128::is_power_of_two

  • DoubleEndedIterator для ToLowercase

  • DoubleEndedIterator для ToUppercase

  • TryFrom<&mut [T]> for [T; N]

  • UnwindSafe для Once

  • RefUnwindSafe для Once

  • armv8 neon intrinsics для aarch64

Следующие ранее стабилизированные API стали const:

  • mem::MaybeUninit::as_ptr

  • mem::MaybeUninit::assume_init

  • mem::MaybeUninit::assume_init_ref

  • ffi::CStr::from_bytes_with_nul_unchecked

Прочие изменения

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

Участники 1.59.0

Множество людей объединились для создания Rust 1.59.0. Мы не смогли бы сделать это без всех вас. Спасибо!

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

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

Над публикацией данного перевода работали @belanchuk, @TelegaOvoshey, @funkill, @ozkriff и @MaybeWaffle.

Комментарии (7)


  1. flx0
    26.02.2022 19:24
    +2

    const-генерики всё еще очень слабые. Тип const-генерика обязан иметь выведенный (аннотацией derive) трейт PartialEq.
    Это в принципе логично — так компилятор может сравнивать константы на этапе компиляции. Но можно было бы сравнивать, и, к примеру, ссылки, ведущие на один и тот же немутабельный объект. Так можно вынести некоторые проверки на этап компиляции.


    1. MaybeWaffle Автор
      26.02.2022 19:41
      +1

      Мне кажется вы что-то перепутали, сейчас в стабильном расте тип const-generic параметра вообще может быть только числом, bool и char, свои типы нельзя использовать даже с #[derive(PartialEq)].

      Подобное ограничение есть в паттерн матчинге, там константные паттерны работают только с типами у которых есть derive(PartialEq, Eq), но там и ссылки работают:

      #[derive(PartialEq, Eq)]
      struct Derived(i32);
      struct Manual(i32);
      
      impl Eq for Manual {}
      impl PartialEq for Manual { ... }
      
      const D: Derived = Derived(0);
      const DR: &'static Derived = &Derived(0);
      const M: Manual = Manual(0);
      
      match Manual(1) {
          // error: to use a constant of type `Manual` in a pattern, `Manual` must be annotated with `#[derive(PartialEq, Eq)]`
          M => println!("zero???"),
          _ => println!("non-zero :("),
      }
      
      match Derived(1) {
        D => println!("zero!"), // ok
        _ => println!("non-zero :("),
      }
      
      match &Derived(1) {
        DR => println!("zero!"), // ok
        _ => println!("non-zero :("),
      }
      


      1. flx0
        26.02.2022 20:33
        +1

        PartialEq работает в Nightly с #![feature(adt_const_params)]. В стейбле еще более грустно, да.


  1. maxim_ge
    26.02.2022 21:03
    +4

    Пример с деструктурирующим присваиванием я бы переписал в таком песочницо-компилируемом виде:


    fn main() {
    
        let (a, b, c, d, e);
    
        (a, b) = (1, 2);
        [c, .., d, _] = [1, 2, 3, 4, 5];
    
        struct EF {
            e: i32,
            #[allow(unused)]        
            f: i32,
        }
    
        EF { e, .. } = EF { e: 5, f: 3 };
    
        assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
    }


  1. warlock13
    27.02.2022 15:40
    +4

    [политическое сообщение удалено из-за правил хабра]

    Это правило было написано когда не было войны. Нет ни малейшего смысла соблюдать его сейчас.


    1. ozkriff
      27.02.2022 16:52
      +2

      я удивлен, что полный перевод аж почти целые сутки провисел пока модераторы до него не добрались. ну и логика их действий понятна - боятся, что иначе весь хабр прикроют :/


    1. diaevd
      01.03.2022 01:35

      Это правило должно действовать всегда.