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_ifvec::ExtractIfLinkedList::extract_iflinked_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_mutString::extend_from_withinos_str::DisplayOsString::displayOsStr::displayio::pipeio::PipeReaderio::PipeWriterimpl From<PipeReader> for OwnedHandleimpl From<PipeWriter> for OwnedHandleimpl From<PipeReader> for Stdioimpl From<PipeWriter> for Stdioimpl From<PipeReader> for OwnedFdimpl From<PipeWriter> for OwnedFdBox<MaybeUninit<T>>::writeimpl 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_unsignedNonNull::offset_from_unsignedNonNull::byte_offset_from_unsigned<uN>::cast_signedNonZero::<uN>::cast_signed<iN>::cast_unsignedNonZero::<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_sliceSocketAddr::set_ipSocketAddr::set_port,SocketAddrV4::set_ipSocketAddrV4::set_port,SocketAddrV6::set_ipSocketAddrV6::set_portSocketAddrV6::set_flowinfoSocketAddrV6::set_scope_idchar::is_digitchar::is_whitespace<[[T; N]]>::as_flattened<[[T; N]]>::as_flattened_mutString::into_bytesString::as_strString::capacityString::as_bytesString::lenString::is_emptyString::as_mut_strString::as_mut_vecVec::as_ptrVec::as_sliceVec::capacityVec::lenVec::is_emptyVec::as_mut_sliceVec::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 вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.
