Команда Rust рада сообщить о новой версии языка — 1.64.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.
Если у вас есть предыдущая версия Rust, установленная через rustup
, то для обновления до версии 1.64.0 вам достаточно выполнить команду:
rustup update stable
Если у вас ещё нет rustup
, то можете установить его со страницы на нашем веб-сайте, а также ознакомиться с подробным описанием выпуска 1.64.0 на GitHub.
Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать beta (rustup default beta
) или nightly (rustup default nightly
) канал. Пожалуйста, сообщайте обо всех встреченных вами ошибках.
Что стабилизировано в 1.64.0
Улучшение .await
с помощью IntoFuture
В Rust 1.64 стабилизирован трейт IntoFuture
. Он похож на трейт IntoIterator
, но вместо поддержки циклов for ... in ...
, IntoFuture
изменяет поведение .await
. С IntoFuture
ключевое слово .await
может применяться не только на футурах, но и на всём, что может быть преобразовано в Future
при помощи IntoFuture
, что сделает ваше API более простым для использования!
Возьмём, к примеру, билдер, который создаёт запрос к некоторому сетевому хранилищу:
pub struct Error { ... }
pub struct StorageResponse { ... }:
pub struct StorageRequest(bool);
impl StorageRequest {
/// Создать новый экземпляр `StorageRequest`.
pub fn new() -> Self { ... }
/// Решить, будет ли включён отладочный режим.
pub fn set_debug(self, b: bool) -> Self { ... }
/// Отправить запрос и получить ответ.
pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}
Типичное использование, вероятно, будет выглядеть так:
let response = StorageRequest::new() // 1. Создать экземпляр
.set_debug(true) // 2. Установить некоторые настройки
.send() // 3. Сконструировать Future
.await?; // 4. Запустить Future + пробросить ошибки
Это уже неплохо, но мы можем сделать лучше. Используя IntoFuture
, мы можем сделать за один шаг "создание футуры" (строка 3) и "запуск футуры" (строка 4):
let response = StorageRequest::new() // 1. Создать экземпляр
.set_debug(true) // 2. Установить некоторые настройки
.await?; // 3. Сконструировать + запустить Future + пробросить ошибки
Мы можем сделать это, реализовав IntoFuture
для StorageRequest
. IntoFuture
требует от нас наличия именованной футуры, которую мы возвращаем. Её мы можем создать упакованной и объявить для неё псевдоним:
// Сначала мы должны импортировать в область видимости несколько новых типов.
use std::pin::Pin;
use std::future::{Future, IntoFuture};
pub struct Error { ... }
pub struct StorageResponse { ... }
pub struct StorageRequest(bool);
impl StorageRequest {
/// Создадим новый экземпляр `StorageRequest`.
pub fn new() -> Self { ... }
/// Решим, следует ли включить режим отладки.
pub fn set_debug(self, b: bool) -> Self { ... }
/// Отправим запрос и получим ответ
pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}
// Новая имплементация
// 1. Создадим новый именованный тип футуры
// 2. Имплементируем `IntoFuture` для `StorageRequest`
pub type StorageRequestFuture = Pin<Box<dyn Future<Output = Result<StorageResponse, Error> + Send + 'static>>
impl IntoFuture for StorageRequest {
type IntoFuture = StorageRequestFuture;
type Output = <StorageRequestFuture as Future>::Output;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.send())
}
}
Это требует немного больше кода для реализации, но предоставляет более простой API для пользователей.
Мы надеемся, что в будущем Rust Async WG упростит создание новой именованной футуры при помощи impl Trait
в type
("Type Alias Impl Trait" или TAIT). Это должно облегчить реализацию IntoFuture
за счёт упрощения сигнатуры псевдонима и улучшить производительность за счёт удаления из псевдонима упаковки (Box
).
C-совместимые типы FFI в core и alloc
Вызывая или будучи вызванным C ABI, код Rust может использовать псевдонимы типов, такие как c_uint
или c_ulong
для сопоставления соответствующих типов из C на любой целевой сборке, не требуя специализированного кода или условий.
Раньше эти псевдонимы типов были доступны только в std
, поэтому код, написанный для встроенных систем и других сценариев, которые могли использовать только core
или alloc
, не мог использовать эти типы.
Rust 1.64 теперь предоставляет все псевдонимы типа c_*
в core::ffi
, а также core::ffi::CStr
для работы со строками C. Rust 1.64 также предоставляет alloc::ffi::CString
для работы с собственными строками C, используя только крейт alloc
, а не полную библиотеку std
.
Rust-analyzer теперь доступен через rustup
Rust-analyzer теперь входит в набор инструментов, включённых в Rust. Это упрощает загрузку и доступ к rust-analyzer, а также делает его доступным на большем количестве платформ. Он доступен как компонент rustup, который можно установить с помощью:
rustup component add rust-analyzer
В настоящее время, чтобы запустить версию, установленную rustup, вам нужно вызвать её следующим образом:
rustup run stable rust-analyzer
В следующем выпуске rustup предоставит встроенный прокси-сервер, так что при запуске исполняемого файла rust-analyzer
будет запускаться соответствующая версия.
Большинству пользователей следует продолжать использовать выпуски, предоставленные командой rust-analyzer, которые публикуются чаще. Они доступны на странице выпусков rust-analyzer. Это не затрагивает пользователей официального расширения VSCode, поскольку оно автоматически загружает и обновляет выпуски в фоновом режиме.
Улучшения Cargo: наследование рабочего пространства и многоцелевые сборки
Теперь при работе с коллекциями связанных библиотек или бинарных крейтов в одном рабочем пространстве Cargo, вы можете избежать дублирования общих значений полей между крейтами, таких как общие номера версий, URL-адреса репозитория или rust-version
. Это также помогает синхронизировать эти значения между крейтами при их обновлении. Дополнительные сведения см. в workspace.package
, workspace.dependencies
и "наследование зависимости от рабочего пространства".
При сборке для нескольких целей вы сможете передать несколько опций --target
в cargo build
, чтобы собрать их все одновременно. Вы также можете установить для build.target
массив из нескольких целей в .cargo/config.toml
, чтобы по умолчанию выполнять сборку для нескольких целей.
Стабилизированные API
Стабилизированы следующие методы и реализации трейтов:
future::IntoFuture
num::NonZero*::checked_mul
num::NonZero*::checked_pow
num::NonZero*::saturating_mul
num::NonZero*::saturating_pow
num::NonZeroI*::abs
num::NonZeroI*::checked_abs
num::NonZeroI*::overflowing_abs
num::NonZeroI*::saturating_abs
num::NonZeroI*::unsigned_abs
num::NonZeroI*::wrapping_abs
num::NonZeroU*::checked_add
num::NonZeroU*::checked_next_power_of_two
num::NonZeroU*::saturating_add
os::unix::process::CommandExt::process_group
os::windows::fs::FileTypeExt::is_symlink_dir
os::windows::fs::FileTypeExt::is_symlink_file
Типы, ранее стабилизированные в std::ffi
и теперь доступные в core
и alloc
:
core::ffi::CStr
core::ffi::FromBytesWithNulError
alloc::ffi::CString
alloc::ffi::FromVecWithNulError
alloc::ffi::IntoStringError
alloc::ffi::NulError
Типы, ранее стабилизированные в std::os::raw
и теперь доступные в core::ffi
и std::ffi
:
ffi::c_char
ffi::c_double
ffi::c_float
ffi::c_int
ffi::c_long
ffi::c_longlong
ffi::c_schar
ffi::c_short
ffi::c_uchar
ffi::c_uint
ffi::c_ulong
ffi::c_ulonglong
ffi::c_ushort
Были стабилизированы несколько вспомогательных функций, которые используются с Poll
, низкоуровневой реализацией футур:
Мы надеемся, что в будущем сможем предоставить более простое API, которое будет требовать меньше использования низкоуровневых деталей, таких как Poll
и Pin
. Но сейчас данные вспомогательные функции упростят написание такого кода.
Следующие API теперь возможно использовать в контексте const
:
Замечания о совместимости
- Как было ранее анонсировано, для компиляции целей
linux
потребуется ядро Linux 3.2 и выше (за исключением тех целей, которые уже требуют более новое ядро). Также целиlinux-gnu
теперь требуют glibc 2.17 (за исключением тех, которые уже требуют более новую glibc). - Rust 1.64.0 изменяет структуру размещения в памяти
Ipv4Addr
,Ipv6Addr
,SocketAddrV4
иSocketAddrV6
, чтобы сделать её более компактной и эффективной. Это внутреннее представление никогда не раскрывалось, но некоторые крейты всё равно полагались на него, используяstd::mem::transmute
, что приводило к недопустимым обращениям к памяти. Такие детали внутренней реализации стандартной библиотеки никогда не считаются стабильным интерфейсом. Чтобы ограничить ущерб, мы работали с авторами всех ещё поддерживаемых крейтов, чтобы выпустить исправленные версии, которые отсутствовали более года. Подавляющее большинство затронутых пользователей будут иметь возможность смягчить последствия с помощьюcargo update
. - В рамках прекращения поддержки RLS это также последний выпуск, содержащий копию RLS. Начиная с Rust 1.65.0, RLS будет заменён небольшим сервером LSP, показывающим предупреждение об устаревании.
Прочие изменения
Выпуск Rust 1.64 включает и другие изменения:
- Компилятор Rust для Windows теперь собирается с PGO, что даёт прирост производительности при компилировании кода на 10-20%.
- Если вы объявляли структуру, содержащую поле, которое никогда не используется, то rustc об этом предупреждал. Теперь вы можете включить проверку
unused_tuple_struct_fields
, чтобы получить аналогичное предупреждение о неиспользуемых полях в кортежных структурах. В будущих версиях мы планируем включить эту проверку по умолчанию. Для полей единичного типа (()
) такое предупреждение не будет генерироваться для облегчения миграции существующего кода без изменения индексов кортежа.
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Участники 1.64.0
Многие люди собрались вместе, чтобы создать Rust 1.64.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.
Данную статью совместными усилиями перевели andreevlex TelegaOvoshey и funkill.
DarkEld3r
Кто-нибудь может объяснить мне эту часть? Получается, что если есть кортеж вида
(u8, (), u16)
и "среднее" поле не используется, то предупреждения не будет?.. Но к чему тут "облегчения миграции существующего кода без изменения индексов кортежа"?mayorovp
Ну вот у вас был кортеж вида
(u8, u8, u16)
, и оказалось что второй элемент нигде не используется. Если вы его удалите и получите(u8, u16)
— вам придётся всюду переделывать обращение к третьему элементу на обращение ко второму. Поэтому предлагается использовать вариант(u8, (), u16)
, который столь же оптимален по памяти — но не требует переделывания обращений.DarkEld3r
Теперь дошло, спасибо за объяснение!
Хотя я бы всё-таки поправил индексы, если это, конечно, не публичное апи, которое не хочется лишний раз ломать.