Команда Rust рада сообщить о новой версии языка — 1.85.0, а также о стабилизации 2024-й редакции. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.
Если у вас есть предыдущая версия Rust, установленная через rustup
, то для обновления до версии 1.85.0 вам достаточно выполнить команду:
$ rustup update stable
Если у вас ещё не установлен rustup
, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.
Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать канал beta (rustup default beta
) или nightly (rustup default nightly
). Пожалуйста, сообщайте обо всех встреченных вами ошибках.
Что входит в стабильную версию 1.85.0?
Rust 2024
Мы рады сообщить, что редакция Rust 2024 теперь стабильна! Редакции — это наш механизм для внесения крупных изменений в язык, которые могут привести к нарушению обратной совместимости. Смотрите руководство по редакциям для общей информации о том, как это работает, и получения подробных инструкций по переносу.
Это самая крупная редакция, которую мы когда-либо выпускали. Подробная информация обо всех изменениях содержится в руководстве по редакциям, а здесь мы предоставим краткую выдержку:
- Язык
- RPIT lifetime capture rules — изменили захват параметров по умолчанию с помощью
impl Trait
типов, когда отсутствуетuse<..>
. Временная область if let
— изменили область временных значений для выраженийif let
.- Временная область действия последнего выражения — изменили область действия временных параметров для последних выражений в блоке.
- Соблюдение требований эргономики — запретили некоторые комбинации шаблонов, чтобы избежать путаницы и обеспечить возможность будущих улучшений.
Небезопасные extern
-блоки —extern
блоки теперь требуют ключевое словоunsafe
.- Небезопасные атрибуты — атрибуты
export_name
,link_section
иno_mangle
теперь должны быть помечены какunsafe
. Предупреждение unsafe_op_in_unsafe_fn
— проверкаunsafe_op_in_unsafe_fn
теперь по умолчанию предупреждающая и требует явных блоковunsafe {}
вunsafe
-функции.Запрет ссылки на static mut
— ссылки наstatic mut
теперь запрещены по умолчанию и генерируют ошибку.- Изменение поведения приведения типа Never к любому другому — изменили способ принудительного вывода
!
, а также меняет поведение проверкиnever_type_fallback_flowing_into_unsafe
на запрещающее. - Спецификаторы фрагмента макроса — спецификатор фрагмента макроса
expr
вmacro_rules!
теперь также соответствует выражениямconst
и_
. - Отсутствующие спецификаторы фрагмента макроса — проверка
missing_fragment_specifier
теперь вызывает серьёзную ошибку, отклоняющую мета-переменные макроса без указания типа спецификатора фрагмента. Ключевое слово gen
— ключевое словоgen
зарезервировано в ожидании добавления в будущем блоков генераторов.- Зарезервированный синтаксис строк — зарезервировали строки стиля
#"foo"#
и токены##
в ожидании изменения способа анализа защищённых строковых литералов в будущем.
- RPIT lifetime capture rules — изменили захват параметров по умолчанию с помощью
- Стандартная библиотека
- Изменения в прелюдии — добавили в прелюдию
Future
иIntoFuture
. Добавили IntoIterator
дляBox<[T]>
— изменили способ работы итераторов со срезами в куче.- Новые unsafe-функции —
std::env::set_var
,std::env::remove_var
иstd::os::unix::process::CommandExt::before_exec
теперь являются небезопасными функциями.
- Изменения в прелюдии — добавили в прелюдию
- Cargo
- Cargo: распознаватель, учитывающий версию Rust — изменили поведение распознавателя зависимостей по умолчанию, теперь он учитывает поле
rust-version
. - Cargo: согласованность имён таблиц и ключей — удалили некоторые устаревшие ключи
Cargo.toml
. Cargo: отклонение неиспользуемых унаследованных default-features
— изменили способ работыdefault-features = false
с унаследованными зависимостями рабочей области.
- Cargo: распознаватель, учитывающий версию Rust — изменили поведение распознавателя зависимостей по умолчанию, теперь он учитывает поле
- Rustdoc
- Комбинированные тесты Rustdoc — документационные тесты теперь объединены в один исполняемый файл, что значительно повышает производительность.
Rustdoc: изменение вложенных include!
— изменение относительного пути ко вложенным файламinclude!
.
- Rustfmt
- Rustfmt: стили редакций — представляем концепцию "стилей редакций", которая позволяет независимо управлять форматированием с учётом редакции Rust.
- Rustfmt: исправления форматирования — большое количество исправлений для форматирования различных ситуаций.
- Rustfmt: сортировка необработанных идентификаторов — изменили способ сортировки идентификаторов
r#foo
. - Rustfmt: сортировка по версиям — изменили способ сортировки идентификаторов, содержащих целые числа.
Переход на редакцию 2024
Руководство содержит инструкции по переносу всех новых функций и в целом по переводу существующего проекта в новую редакцию. Во многих случаях cargo fix
позволяет автоматизировать необходимые изменения. Возможно, вы даже обнаружите, что для перехода на редакцию 2024 вообще не потребуется вносить никаких изменений в ваш код!
Обратите внимание, что автоматические исправления с помощью cargo fix
очень консервативны и будут избегать изменения семантики вашего кода. Во многих случаях вы захотите сохранить свой код прежним, используя при этом новую семантику Rust 2024. Например, продолжая использовать средство сопоставления макросов expr
и игнорируя преобразования условных выражений, потому что вам нужна новая семантика порядка выполнения Drop
. Результат cargo fix
не следует рассматривать как рекомендацию, это просто консервативное преобразование, которое сохраняет поведение.
Над созданием этого издания работало множество людей. Мы хотели бы поблагодарить их всех за усердную работу!
async
closures
Rust теперь поддерживает асинхронные замыкания, такие как async ||{}
, которые при вызове возвращают футуры. Они работают подобно async fn
, которые также могут захватывать значения из локальной среды. Разница между ними точно такая же, как между обычными замыканиями и функциями. Эта функциональность также включает в себя 3 аналогичных трейта в прелюдии стандартной библиотеки: AsyncFn
, AsyncFnMut
и AsyncFnOnce
.
В некоторых случаях вы могли создать нечто подобное с помощью обычного замыкания и асинхронного блока, например || async {}
— но футура, возвращаемая таким внутренним блоком, не может быть заимствована из перехватов замыкания. Однако это работает с async
-замыканиями:
let mut vec: Vec<String> = vec![];
let closure = async || {
vec.push(ready(String::from("")).await);
};
Также было невозможно правильно выразить сигнатуры функций более высокого ранга с помощью трейтов Fn
, возвращающих Future
. Впрочем, вы могли сделать это с помощью трейтов AsyncFn
:
use core::future::Future;
async fn f<Fut>(_: impl for<'a> Fn(&'a u8) -> Fut)
where
Fut: Future<Output = ()>,
{ todo!() }
async fn f2(_: impl for<'a> AsyncFn(&'a u8))
{ todo!() }
async fn main() {
async fn g(_: &u8) { todo!() }
f(g).await;
//~^ ERROR mismatched types
//~| ERROR one type is more general than the other
f2(g).await; // ok!
}
Таким образом, async
-замыкания предоставляют первоклассные решения для обеих этих проблем! Более подробную информацию смотрите в RFC 3668 и в отчёте о стабилизации.
Скрытие реализаций трейтов от диагностики
Новый атрибут #[diagnostic::do_not_recommend]
является подсказкой компилятору не показывать аннотированную реализацию трейта как часть диагностического сообщения. Для авторов библиотек это способ уберечь компилятор от внесения предложений, которые могут оказаться бесполезными или вводящими в заблуждение. Например:
pub trait Foo {}
pub trait Bar {}
impl<T: Foo> Bar for T {}
struct MyType;
fn main() {
let _object: &dyn Bar = &MyType;
}
error[E0277]: the trait bound `MyType: Bar` is not satisfied
--> src/main.rs:9:29
|
9 | let _object: &dyn Bar = &MyType;
| ^^^^ the trait `Foo` is not implemented for `MyType`
|
note: required for `MyType` to implement `Bar`
--> src/main.rs:4:14
|
4 | impl<T: Foo> Bar for T {}
| --- ^^^ ^
| |
| unsatisfied trait bound introduced here
= note: required for the cast from `&MyType` to `&dyn Bar`
Для некоторых API может иметь смысл реализовать Foo
и косвенно получить Bar
с помощью этой общей реализации. Для других можно было бы ожидать, что большинство пользователей должны напрямую реализовывать Bar
, так что предложение Foo
будет только сбивать их с толку. В этом случае добавление диагностической подсказки изменит сообщение об ошибке следующим образом:
#[diagnostic::do_not_recommend]
impl<T: Foo> Bar for T {}
error[E0277]: the trait bound `MyType: Bar` is not satisfied
--> src/main.rs:10:29
|
10 | let _object: &dyn Bar = &MyType;
| ^^^^ the trait `Bar` is not implemented for `MyType`
|
= note: required for the cast from `&MyType` to `&dyn Bar`
Смотрите RFC 2397, чтобы узнать первоначальную мотивацию изменения и текущий reference для получения более подробных деталей.
FromIterator
и Extend
для кортежей
В более ранних версиях Rust были реализованы удобные функции для итераторов из пар кортежей (T, U)
, которые вели себя как Iterator::unzip
, с Extend
в версии 1.56 и FromIterator
в версии 1.79. Теперь они были расширены для большего количества кортежей, начиная с одноэлементного (T,)
и заканчивая кортежами длиной в 12 элементов, (T1, T2, .., T11, T12)
. Например, теперь вы можете использовать collect()
для создания нескольких коллекций одновременно:
use std::collections::{LinkedList, VecDeque};
fn main() {
let (squares, cubes, tesseracts): (Vec<_>, VecDeque<_>, LinkedList<_>) =
(0i32..10).map(|i| (i * i, i.pow(3), i.pow(4))).collect();
println!("{squares:?}");
println!("{cubes:?}");
println!("{tesseracts:?}");
}
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
[0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]
Обновления в std::env::home_dir()
std::env::home_dir()
уже много лет считается устаревшим, поскольку может давать неожиданные результаты в некоторых конфигурациях Windows, когда установлена переменная среды HOME
(что не является ситуацией по умолчанию). Ранее мы избегали изменений этой функции из-за вопросов совместимости с кодом, зависящим от этой нестандартной конфигурации. Но, учитывая, как долго эта функция была устаревшей, мы сейчас обновляем её поведение заодно с исправлением других ошибок, так что в следующих выпусках она больше не будет помечена устаревшей.
Стабилизированные API
BuildHasherDefault::new
ptr::fn_addr_eq
io::ErrorKind::QuotaExceeded
io::ErrorKind::CrossesDevices
{float}::midpoint
Беззнаковые {integer}::midpoint
NonZeroU*::midpoint
impl std::iter::Extend
для кортежей с размерностью от 1 до 12FromIterator<(A, ...)>
для кортежей с размерностью от 1 до 12std::task::Waker::noop
Следующие API теперь можно использовать в контексте const
:
mem::size_of_val
mem::align_of_val
Layout::for_value
Layout::align_to
Layout::pad_to_align
Layout::extend
Layout::array
std::mem::swap
std::ptr::swap
NonNull::new
HashMap::with_hasher
HashSet::with_hasher
BuildHasherDefault::new
<float>::recip
<float>::to_degrees
<float>::to_radians
<float>::max
<float>::min
<float>::clamp
<float>::abs
<float>::signum
<float>::copysign
MaybeUninit::write
Прочие изменения
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Кто работал над 1.85.0
Многие люди собрались вместе, чтобы создать Rust 1.85.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.