Rust 1.87.0 и 10 лет Rust!
Команда Rust празднует 10-летие Rust в Утрехте, Нидерланды, и рада сообщить о новой версии языка — 1.87.0!

Сегодняшний день релиза выпал на 10-летний юбилей выхода Rust 1.0!
Спасибо мириадам участников, кто работал или работает над Rust. Выпьем за ещё многие десятилетия впереди! ?
Как обычно, новая версия включает в себя все изменения, которые были внесены в бета-версию за последние шесть недель согласно последовательному и регулярному циклу выпуска. Мы следуем ему начиная с Rust 1.0.
Если у вас есть предыдущая версия Rust, установленная через rustup
, то для обновления до версии 1.87.0 вам достаточно выполнить команду:
$ rustup update stable
Если у вас ещё не установлен rustup
, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.
Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать канал beta (rustup default beta
) или nightly (rustup default nightly
). Пожалуйста, сообщайте обо всех встреченных вами ошибках.
Что стабилизировано в 1.87.0
Анонимные конвейеры
1.87 даёт доступ из стандартной библиотеки к анонимным каналам, включая интеграцию с методами ввода/вывода std::process::Command
. Например, объединить stdout
и stderr
в один поток теперь относительно просто, в то время как раньше необходимо было использовать разные потоки или платформо-специфические функции.
use std::process::Command;
use std::io::Read;
let (mut recv, send) = std::io::pipe()?;
let mut command = Command::new("path/to/bin")
// И stdout, и stderr теперь пишут в один канал.
.stdout(send.try_clone()?)
.stderr(send)
.spawn()?;
let mut output = Vec::new();
recv.read_to_end(&mut output)?;
// Обратите внимание, что что мы читаем из канала до завершения процесса, для исключения
// переполнения буфера ОС, если программа создаст очень много вывода.
assert!(command.wait()?.success());
Безопасные архитектурные интринсики
Большинство интринсиков из std::arch
, которые небезопасны только из-за того, что требуют включения таргет-фич, теперь могут быть вызваны из безопасного кода, в котором эти фичи включены. Например, следующая программа, реализующая суммирование элементов массива с использованием ручных интринсиков, теперь использует безопасный код в основном цикле.
#![forbid(unsafe_op_in_unsafe_fn)]
use std::arch::x86_64::*;
fn sum(slice: &[u32]) -> u32 {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
// БЕЗОПАСНОСТЬ: Во время работы мы удостоверились, что необходимая функциональность присутствует,
// так что вызывать эту функицю безопасно.
return unsafe { sum_avx2(slice) };
}
}
slice.iter().sum()
}
#[target_feature(enable = "avx2")]
#[cfg(target_arch = "x86_64")]
fn sum_avx2(slice: &[u32]) -> u32 {
// БЕЗОПАСНОСТЬ: __m256i и u32 одинаково валидны.
let (prefix, middle, tail) = unsafe { slice.align_to::<__m256i>() };
let mut sum = prefix.iter().sum::<u32>();
sum += tail.iter().sum::<u32>();
// Основной цикл теперь полностью состоит из безопасного кода, потому что интринсики, требующие таргет фичу (avx2),
// упакованы в саму функцию.
let mut base = _mm256_setzero_si256();
for e in middle.iter() {
base = _mm256_add_epi32(base, *e);
}
// БЕЗОПАСНОСТЬ: __m256i и u32 одинаково валидны.
let base: [u32; 8] = unsafe { std::mem::transmute(base) };
sum += base.iter().sum::<u32>();
sum
}
asm!
прыжки в Rust-код
Встроенный ассемблер (asm!
) теперь может прыгать в помеченные участки Rust-кода. Это делает более гибким низкоуровневое программирование — например, реализацию оптимизированного контроля управления в ядрах ОС или более эффективное взаимодействие с железом.
- Макрос
asm!
теперь поддерживает операндlabel
, который работает как переход к метке - Метка должна быть блочным выражением с возвращаемым типом
()
или!
- Блок выполняется, когда на него совершается прыжок. Выполнение продолжается после блока
asm!
. - Использование операндов
output
иlabel
в одном вызовеasm!
остаётся unstable.
unsafe {
asm!(
"jmp {}",
label {
println!("Выскочил из asm!");
}
);
}
Больше информации можно найти в reference.
Прецизионный захват (+ use<...>
) в impl Trait
в объявлении трейтов
В этом выпуске стабилизировано указание конкретных захваченных обобщённых типов и времён жизни в объявлениях трейтов с использованием возвращаемых типов impl Trait
. Благодаря чему теперь можно использовать эту функцию в определениях трейтов, расширяя возможности стабилизации для функций, не связанных с трейтами, в 1.82.
Несколько примеров:
trait Foo {
fn method<'a>(&'a self) -> impl Sized;
// ... преобразуется во что-то вроде:
type Implicit1<'a>: Sized;
fn method_desugared<'a>(&'a self) -> Self::Implicit1<'a>;
// ... а при прецезионном захвате ...
fn precise<'a>(&'a self) -> impl Sized + use<Self>;
// ... преобразуется во что-то подобное:
type Implicit2: Sized;
fn precise_desugared<'a>(&'a self) -> Self::Implicit2;
}
Стабилизированные API
Vec::extract_if
vec::ExtractIf
LinkedList::extract_if
linked_list::ExtractIf
<[T]>::split_off
<[T]>::split_off_mut
<[T]>::split_off_first
<[T]>::split_off_first_mut
<[T]>::split_off_last
<[T]>::split_off_last_mut
String::extend_from_within
os_str::Display
OsString::display
OsStr::display
io::pipe
io::PipeReader
io::PipeWriter
impl From<PipeReader> for OwnedHandle
impl From<PipeWriter> for OwnedHandle
impl From<PipeReader> for Stdio
impl From<PipeWriter> for Stdio
impl From<PipeReader> for OwnedFd
impl From<PipeWriter> for OwnedFd
Box<MaybeUninit<T>>::write
impl TryFrom<Vec<u8>> for String
<*const T>::offset_from_unsigned
<*const T>::byte_offset_from_unsigned
<*mut T>::offset_from_unsigned
<*mut T>::byte_offset_from_unsigned
NonNull::offset_from_unsigned
NonNull::byte_offset_from_unsigned
<uN>::cast_signed
NonZero::<uN>::cast_signed
<iN>::cast_unsigned
NonZero::<iN>::cast_unsigned
<uN>::is_multiple_of
<uN>::unbounded_shl
<uN>::unbounded_shr
<iN>::unbounded_shl
<iN>::unbounded_shr
<iN>::midpoint
<str>::from_utf8
<str>::from_utf8_mut
<str>::from_utf8_unchecked
<str>::from_utf8_unchecked_mut
Следующие API теперь можно использовать в контексте const
:
core::str::from_utf8_mut
<[T]>::copy_from_slice
SocketAddr::set_ip
-
SocketAddr::set_port
, SocketAddrV4::set_ip
-
SocketAddrV4::set_port
, SocketAddrV6::set_ip
SocketAddrV6::set_port
SocketAddrV6::set_flowinfo
SocketAddrV6::set_scope_id
char::is_digit
char::is_whitespace
<[[T; N]]>::as_flattened
<[[T; N]]>::as_flattened_mut
String::into_bytes
String::as_str
String::capacity
String::as_bytes
String::len
String::is_empty
String::as_mut_str
String::as_mut_vec
Vec::as_ptr
Vec::as_slice
Vec::capacity
Vec::len
Vec::is_empty
Vec::as_mut_slice
Vec::as_mut_ptr
Удаление таргета i586-pc-windows-msvc
Таргет i586-pc-windows-msvc
удалён из Tier 2. Отличие i586-pc-windows-msvc
от более популярного таргета i686-pc-windows-msvc
из Tier 1 в том, что i586-pc-windows-msvc
не требует поддержки инструкций SSE2. Но Windows 10, минимально допустимая версия ОС для всех windows
-таргетов (за исключением win7
), сама по себе требует инструкций SSE2.
Все пользователи, использующие в качестве целевой платформы i586-pc-windows-msvc
, должны мигрировать на i686-pc-windows-msvc
.
Для большей информации вы можете изучить Major Change Proposal.
Прочие изменения
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Кто работал над 1.87.0
Многие люди собрались вместе, чтобы создать Rust 1.87.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.