- PVSM.RU - https://www.pvsm.ru -

Rust 1.65.0: GAT, let-else, break от помеченных блоков, отказ от RLS

Команда Rust рада сообщить о новой версии языка — 1.65.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.

Если у вас есть предыдущая версия Rust, установленная через rustup, то для обновления до версии 1.65.0 вам достаточно выполнить команду:

rustup update stable

Если у вас ещё нет rustup, то можете установить его со страницы на нашем веб-сайте, а также ознакомиться с подробным описанием выпуска 1.65.0 [1] на GitHub.

Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать beta (rustup default beta) или nightly (rustup default nightly) канал. Пожалуйста, сообщайте [2] обо всех встреченных вами ошибках.

Что стабилизировано в 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'ы довольно универсальны и позволяют использовать ряд шаблонов, которые сейчас нельзя написать. Для получения дополнительной информации, смотрите прошлогодний пост [3], в котором было анонсировано принятие решения о работе над ними — или пост о стабилизации [4], опубликованный на прошлой неделе. Первый углубляется в приведённые выше примеры, а второй рассказывает об ограничениях текущей реализации.

Больше деталей можно найти в секции ассоциированных типов справочника nightly [5] или в оригинальном RFC [6] (который был открыт более 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 letelse. Раньше вы могли аппроксимировать эти шаблоны неудачным повторением и внешним 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 команда компилятора добавила поддержку разделения отладочной информации [7] в macOS — и теперь эта опция стабильна для использования и в Linux.

  • -Csplit-debuginfo=unpacked разделит отладочную информацию на несколько .dwo — объектных файлов DWARF.
  • -Csplit-debuginfo=packed создаст один DWARF-пакет .dwp вместе с вашим выходным двоичным файлом со всей отладочной информацией, упакованной вместе.
  • -Csplit-debuginfo=off по-прежнему является поведением по умолчанию, которое включает данные DWARF в .debug_* ELF-объектов и окончательный двоичный файл.

Split DWARF позволяет компоновщику избежать обработки отладочной информации (поскольку её больше нет в компонуемых объектных файлах), что может ускорить время компоновки!

Другие цели теперь также принимают -Csplit-debuginfo в качестве стабильной опции со своим значением по умолчанию для конкретной платформы, но указание других значений по-прежнему нестабильно.

Стабилизированные API

Стабилизированы следующие методы и реализации трейтов:

Особо отметим, что Backtrace API позволяет захватить трассировку стека в любое время, используя те же платформо-зависимые реализации, которые обычно используются в трассировке паники. Это может быть полезно, например, для ошибок контекста времени выполнения.

Следующие API теперь возможно использовать в контексте const:

Замечания о совместимости

  • В качестве заключительного шага отказа от RLS [14], в данном выпуске RLS заменяется небольшим LSP-сервером, который показывает предупреждение об отказе, советующем перейти на rust-analyzer.

Прочие изменения

Выпуск Rust 1.65 включает и другие изменения:

  • MIR inlining теперь включено для оптимизированной компиляции. Это позволяет улучшить компиляцию на 3-10% для крейтов.
  • При планировании сборок Cargo теперь сортирует очередь ожидающих заданий для повышения производительности.

Проверьте всё, что изменилось в Rust [1], Cargo [15] и Clippy [16].

Участники 1.65.0

Многие люди собрались вместе, чтобы создать Rust 1.65.0. Без вас мы бы не справились. Спасибо! [17]

От переводчиков

С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате [18] или же в аналогичном чате для новичковых вопросов [19]. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков [20].

Данную статью совместными усилиями перевели andreevlex [21], TelegaOvoshey [22] и funkill [23].

Автор:
RustLangRu

Источник [24]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/380226

Ссылки в тексте:

[1] подробным описанием выпуска 1.65.0: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1650-2022-11-03

[2] сообщайте: https://github.com/rust-lang/rust/issues/new/choose

[3] прошлогодний пост: https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html

[4] пост о стабилизации: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html

[5] справочника nightly: https://doc.rust-lang.org/nightly/reference/items/associated-items.html#associated-types

[6] оригинальном RFC: https://rust-lang.github.io/rfcs/1598-generic_associated_types.html

[7] разделения отладочной информации: https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#splitting-debug-information

[8] std::backtrace::Backtrace: https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html

[9] Bound::as_ref: https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.as_ref

[10] std::io::read_to_string: https://doc.rust-lang.org/stable/std/io/fn.read_to_string.html

[11] <*const T>::cast_mut: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_mut

[12] <*mut T>::cast_const: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_const

[13] <*const T>::offset_from: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from

[14] отказа от RLS: https://blog.rust-lang.org/2022/07/01/RLS-deprecation.html

[15] Cargo: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-165-2022-11-03

[16] Clippy: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-165

[17] Спасибо!: https://thanks.rust-lang.org/rust/1.65.0/

[18] русскоязычном Телеграм-чате: https://t.me/rustlang_ru

[19] чате для новичковых вопросов: https://t.me/rust_beginners_ru

[20] чат переводчиков: https://t.me/rustlang_ru_translations

[21] andreevlex: https://habr.com/ru/users/andreevlex/

[22] TelegaOvoshey: https://habr.com/ru/users/telegaovoshey/

[23] funkill: https://habr.com/ru/users/funkill/

[24] Источник: https://habr.com/ru/post/697430/?utm_source=habrahabr&utm_medium=rss&utm_campaign=697430