Команда 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
proc_macro::Span::source_text
u*::{checked_add_signed, overflowing_add_signed, saturating_add_signed, wrapping_add_signed}
i*::{checked_add_unsigned, overflowing_add_unsigned, saturating_add_unsigned, wrapping_add_unsigned}
i*::{checked_sub_unsigned, overflowing_sub_unsigned, saturating_sub_unsigned, wrapping_sub_unsigned}
BTreeSet::{first, last, pop_first, pop_last}
BTreeMap::{first_key_value, last_key_value, first_entry, last_entry, pop_first, pop_last}
Добавлена реализация AsFd
для типов блокировок стандартных потоков для WASIimpl TryFrom<Vec<T>> for Box<[T; N]>
core::hint::black_box
Duration::try_from_secs_{f32,f64}
Option::unzip
std::os::fd
Прочие изменения
Выпуск Rust 1.66 включает и другие изменения:
- Теперь вы можете использовать в шаблонах диапазоны
..=X
. - Linux-сборки теперь используют оптимизированные rustc фронтенд и LLVM бэкенд с LTO и BOLT соответственно, что оптимизирует быстродействие и использование памяти.
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Участники 1.66.0
Многие люди собрались вместе, чтобы создать Rust 1.66.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.
Данную статью совместными усилиями перевели andreevlex, TelegaOvoshey и funkill.
Комментарии (5)
anatolii_kostrygin
19.12.2022 14:04Судя по документации
Option::unzip
всё ещёunstable
mayorovp
19.12.2022 16:02+1Судя по документации, нестабильна только константная версия
Option::unzip
.
Apoheliy
Сарказм:
Ассемблер это тоже
(если сможешь).
domix32
так это вообще для любого языка