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


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


rustup update stable

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


Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать beta (rustup default beta) или nightly (rustup default nightly) канал. Пожалуйста, сообщайте обо всех встреченных вами ошибках.


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


Явные дискриминанты для перечислений с полями


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


#[repr(u8)]
enum Foo {
    A(u8),
    B(i8),
    C(bool) = 42,
}

Ранее вы могли использовать явные дискриминанты в перечислениях, но только если ни один из вариантов не содержал поля. Явные дискриминанты полезны при передаче значения между разными языками и если значение перечисления нужно определить в обоих языках. Например:


#[repr(u8)]
enum Bar {
    A,
    B,
    C = 42,
    D,
}

Здесь перечисление Bar гарантированно будет иметь то же представление в памяти, что и u8. Кроме того, у варианта Bar::C гарантированно есть дискриминант 42. Варианты без явно указанных значений будут иметь дискриминанты, которые автоматически назначаются в соответствии с их порядком в исходном коде, поэтому у Bar::A будет дискриминант 0, у Bar::B будет 1, а у Bar::D будет 43. Без этой функции единственным способом установить явное значение Bar::C было бы добавить 41 ненужный вариант перед ним!


Примечание: в то время как для перечислений без полей можно проверить дискриминант через приведение as (например, Bar::C as u8), Rust не предоставляет способа на уровне языка для доступа к необработанному дискриминанту перечисления с полями. Вместо этого для проверки дискриминанта перечисления с полями необходимо использовать небезопасный в настоящее время код. Поскольку эта функция предназначена для использования с межъязыковым FFI, где уже необходим небезопасный код, мы надеемся, что это не станет слишком большой дополнительной нагрузкой. Пока же если всё, что вам нужно, — это непрозрачный дескриптор дискриминанта, см. функцию std::mem::discriminant.


core::hint::black_box


Когда исследуется или оценивается машинный код, сгенерированный компилятором, бывает полезно отключить оптимизацию для определённых мест. В следующем примере функция push_cap 4 раза вызывает в цикле Vec::push:


fn push_cap(v: &mut Vec<i32>) {
    for i in 0..4 {
        v.push(i);
    }
}

pub fn bench_push() -> Duration {
    let mut v = Vec::with_capacity(4);
    let now = Instant::now();
    push_cap(&mut v);
    now.elapsed()
}

Если вы посмотрите оптимизированный вывод компилятора для x86_64, то заметите, что он выглядит достаточно коротко:


example::bench_push:
  sub rsp, 24
  call qword ptr [rip + std::time::Instant::now@GOTPCREL]
  lea rdi, [rsp + 8]
  mov qword ptr [rsp + 8], rax
  mov dword ptr [rsp + 16], edx
  call qword ptr [rip + std::time::Instant::elapsed@GOTPCREL]
  add rsp, 24
  ret

Фактически вся функция push_cap, которую мы хотели оценить, была оптимизирована!


Мы можем обойти это при помощи новой стабилизированной функции black_box. Функционально black_box не очень интересна: она лишь берёт значение, которое вы ей передали, и возвращает его обратно. Однако внутри компилятор обрабатывает black_box как функцию, которая что-то делает с передаваемым ей вводом и возвращает какое-то значение (как и следует из её названия).


Это очень полезно для отключение оптимизаций — как той, что мы видели выше. Например, мы можем подсказать компилятору, что вектор будет использоваться для чего-то после каждой итерации цикла.


use std::hint::black_box;

fn push_cap(v: &mut Vec<i32>) {
    for i in 0..4 {
        v.push(i);
        black_box(v.as_ptr());
    }
}

Теперь мы можем найти развёрнутый цикл for в нашем оптимизированном ассемблерном выводе:


  mov dword ptr [rbx], 0
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 4], 1
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 8], 2
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 12], 3
  mov qword ptr [rsp + 8], rbx

Вы также можете увидеть побочный эффект вызова black_box в этом ассемблерном выводе. Инструкция mov qword ptr [rsp + 8], rbx бесполезно повторяется после каждой итерации. Эта инструкция записывает адрес v.as_ptr() в качестве первого аргумента функции, которая фактически никогда не вызывается.


Обратите внимание, что сгенерированный код вообще не связан с возможностью распределения памяти, введённого вызовом push. Это потому, что компилятор всё ещё опирается на тот факт, что мы вызвали Vec::with_capacity(4) в функции bench_push. Вы можете поиграть с размещением black_box или попробовать использовать его в нескольких местах, чтобы увидеть его влияние на оптимизацию компилятора.


cargo remove


Rust 1.62.0 представил cargo add — утилиту командной строки для добавления зависимостей в ваш проект. В этой же версии вы сможете использовать cargo remove для их удаления.


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



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


Выпуск Rust 1.66 включает и другие изменения:


  • Теперь вы можете использовать в шаблонах диапазоны ..=X.
  • Linux-сборки теперь используют оптимизированные rustc фронтенд и LLVM бэкенд с LTO и BOLT соответственно, что оптимизирует быстродействие и использование памяти.

Проверьте всё, что изменилось в Rust, Cargo и Clippy.


Участники 1.66.0


Многие люди собрались вместе, чтобы создать Rust 1.66.0. Без вас мы бы не справились. Спасибо!


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


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


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

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


  1. Apoheliy
    18.12.2022 14:52
    +2

    Сарказм:

    Ассемблер это тоже

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

    (если сможешь).


    1. domix32
      18.12.2022 22:28
      +5

      (если сможешь).

      так это вообще для любого языка


  1. anatolii_kostrygin
    19.12.2022 14:04

    Судя по документации Option::unzipвсё ещё unstable


    1. mayorovp
      19.12.2022 16:02
      +1

      Судя по документации, нестабильна только константная версия Option::unzip.


      1. anatolii_kostrygin
        19.12.2022 16:16

        Точно, вы правы, спасибо!