Команда Rust рада сообщить о новой версии языка — 1.65.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.
Если у вас есть предыдущая версия Rust, установленная через rustup, то для обновления до версии 1.65.0 вам достаточно выполнить команду:
rustup update stable
Если у вас ещё нет rustup, то можете установить его со страницы на нашем веб-сайте, а также ознакомиться с подробным описанием выпуска 1.65.0 на GitHub.
Если вы хотите ��омочь нам протестировать будущие выпуски, вы можете использовать beta (rustup default beta) или nightly (rustup default nightly) канал. Пожалуйста, сообщайте обо всех встреченных вами ошибках.
Что стабилизировано в 1.65.0
Генерализованные ассоциативные типы (GAT)
Времена жизни, типы и константные обобщения теперь могут быть объявлены с ассоциированными типами:
trait Foo { type Bar<'x>; }
Сложно в двух словах описать, насколько это может оказаться полезным, так что представим несколько примеров типажей, чтобы прочувствовать их силу:
/// `Iterator`-подобный типаж, который может заимствовать `Self` trait LendingIterator { type Item<'a> where Self: 'a; fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; } /// Может быть реализован через умные указатели, вроде `Rc` или `Arc`, /// так как типаж обобщён для типа указателя. trait PointerFamily { type Pointer<T>: Deref<Target = T>; fn new<T>(value: T) -> Self::Pointer<T>; } /// Разрешается заимствовать массив элементов. Удобно для /// `NdArray`-подобных типов. которым неважно непрерывное хранение данных. trait BorrowArray<T> { type Array<'x, const N: usize> where Self: 'x; fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>; }
Как вы можете видеть, GAT'ы довольно универсальны и позволяют использовать ряд шаблонов, которые сейчас нельзя написать. Для получения дополнительной информации, смотрите прошлогодний пост, в котором было анонсировано принятие решения о работе над ними — или пост о стабилизации, опубликованный на прошлой неделе. Первый углубляется в приведённые выше примеры, а второй рассказывает об ограничениях текущей реализации.
Больше деталей можно найти в секции ассоциированных типов справочника nightly или в оригинальном RFC (который был открыт более 6,5 лет назад!).
let-else выражения
Данный выпуск представляет новый тип оператора let с условным шаблоном и отдельным блоком else, который исполняется при несовпадении образца.
let PATTERN: TYPE = EXPRESSION else { DIVERGING_CODE; };
Обычные операторы let могут использовать только неопровержимые шаблоны, о которых статически известно, что они всегда совпадают. Этот шаблон часто представляет собой просто связывание одной переменной, но может также распаковывать составные типы, такие как структуры, кортежи и массивы. Однако это нельзя было использовать для условных совпадений, например для извлечения варианта перечисления — до сих пор! С помощью let else опровержимый шаблон может сопоставлять и связывать переменные в окружающей области видимости, как обычный let, или расходиться (как break, return, panic!), когда шаблон не совпадает.
fn get_count_item(s: &str) -> (u64, &str) { let mut it = s.split(' '); let (Some(count_str), Some(item)) = (it.next(), it.next()) else { panic!("Can't segment count item pair: '{s}'"); }; let Ok(count) = u64::from_str(count_str) else { panic!("Can't parse integer: '{count_str}'"); }; (count, item) } assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
Область действия привязок имён — это главное, что отличает их от выражений match или if let — else. Раньше вы могли аппроксимировать эти шаблоны неудачным повторением и внешним let:
let (count_str, item) = match (it.next(), it.next()) { (Some(count_str), Some(item)) => (count_str, item), _ => panic!("Can't segment count item pair: '{s}'"), }; let count = if let Ok(count) = u64::from_str(count_str) { count } else { panic!("Can't parse integer: '{count_str}'"); };
break от помеченных блоков
Простые блочные выражения теперь могут быть помечены как цель break, завершающая этот блок раньше. Это может звучать как goto, но это не произвольный переход, а только изнутри блока в его конец. Это уже было возможно с блоками loop, и вы, возможно, видели, как люди пишут циклы, которые всегда выполняются только один раз, просто чтобы получить помеченный break.
Теперь для этого появилась специальная языковая возможность! Помеченный break также может включать значение выражения, как и в случае с циклами, что позволяет блоку с несколькими операторами иметь раннее значение «возврата».
let result = 'block: { do_thing(); if condition_not_met() { break 'block 1; } do_next_thing(); if condition_not_met() { break 'block 2; } do_last_thing(); 3 };
Разделение отладочной информации в Linux
Ещё в Rust 1.51 команда компилятора добавила поддержку разделения отладочной информации в macOS — и теперь эта опция стабильна для использования и в Linux.
-Csplit-debuginfo=unpackedразделит отладочную информацию на несколько.dwo— объектных файлов DWARF.-Csplit-debuginfo=packedсоздаст один DWARF-пакет.dwpвместе с вашим выходным двоичным файлом со всей отладочной информацией, упакованной вместе.-Csplit-debuginfo=offпо-прежнему является поведением по умолчанию, которое включает данные DWARF в.debug_*ELF-объектов и окончательный двоичный файл.
Split DWARF позволяет компоновщику избежать обработки отладочной информации (поскольку её больше нет в компонуемых объектных файлах), что может ускорить время компоновки!
Другие цели теперь также принимают -Csplit-debuginfo в качестве стабильной опции со своим значением по умолчанию для конкретной платформы, но указание других значений по-прежнему нестабильно.
Стабилизированные API
Стабилизированы следующие методы и реализации трейтов:
std::backtrace::BacktraceBound::as_refstd::io::read_to_string<*const T>::cast_mut<*mut T>::cast_const
Особо отметим, что Backtrace API позволяет захватить трассировку стека в любое время, используя те же платформо-зависимые реализации, которые обычно используются в трассировке паники. Это может быть полезно, например, для ошибок контекста времени выполнения.
Следующие API теперь возможно использовать в контексте const:
Замечания о совместимости
- В качестве заключительного шага отказа от RLS, в данном выпуске RLS заменяется небольшим LSP-сервером, который показывает предупреждение об отказе, советующем перейти на
rust-analyzer.
Прочие изменения
Выпуск Rust 1.65 включает и другие изменения:
- MIR inlining теперь включено для оптимизированной компиляции. Это позволяет улучшить компиляцию на 3-10% для крейтов.
- При планировании сборок Cargo теперь сортирует очередь ожидающих заданий для повышения производительности.
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Участники 1.65.0
Многие люди собрались вместе, чтобы создать Rust 1.65.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.
Данную статью совместными усилиями перевели andreevlex, TelegaOvoshey и funkill.