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

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

$ rustup update stable

Если Rust ещё не установлен, вы можете получить rustup на соответствующей странице нашего сайта и ознакомиться с подробными release notes для 1.96.0.

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

Что нового в stable 1.96.0

Новые типы Range*

Многие пользователи ожидают, что Range и связанные типы из core::ops будут реализовывать Copy, но это не так: они напрямую реализуют Iterator, а реализовывать одновременно Iterator и Copy для одного типа — плохая идея, поэтому от этого сознательно отказались. RFC3550 предложил набор заменяющих типов диапазонов, которые реализуют IntoIterator, а не Iterator, и поэтому могут также реализовывать Copy. Часть этого RFC, относящаяся к стандартной библиотеке, теперь стабилизирована и добавляет:

  • core::range::Range

  • core::range::RangeFrom

  • core::range::RangeInclusive

  • Сопутствующие итераторы

В одной из ближайших версий Rust также появятся core::range::RangeFull и core::range::RangeTo как re-export из core::ops (они не реализуют Iterator и уже реализуют Copy), а также core::range::legacy::* как новое место для текущих типов диапазонов. Синтаксис диапазонов вроде 0..1 пока по-прежнему создаёт legacy-типы, но в будущей edition будет обновлён на типы из core::range.

Благодаря этим стабилизациям теперь можно хранить аксессоры срезов в типах с Copy, не разделяя start и end:

use core::range::Range;

#[derive(Clone, Copy)]
pub struct Span(Range<usize>);

impl Span {
    pub fn of(self, s: &str) -> &str {
        &s[self.0]
    }
}

У нового RangeInclusive поля также публичные — в отличие от legacy-версии, которая избегала раскрывать состояние исчерпанного итератора. Для нового типа это не проблема, поскольку для начала итерации его нужно явно преобразовать.

Авторам библиотек стоит использовать в публичном API impl RangeBounds, который принимает и legacy-, и новые типы диапазонов. Если нужен конкретный тип, предпочтительнее использовать новые диапазоны — со временем они станут стандартом по умолчанию.

Проверка соответствия паттерну

Новые макросы assert_matches! и debug_assert_matches! проверяют, что значение соответствует заданному паттерну, и в противном случае вызывают panic с Debug-представлением значения. По сути это то же самое, что assert!(matches!(..)) и debug_assert!(matches!(..)), но выводимое значение упрощает диагностику сбоя.

Эти макросы не добавлены в стандартный prelude, потому что их имена конфликтуют с популярными сторонними crate, предоставляющими макросы с теми же названиями. Вместо этого их нужно вручную импортировать из core или std перед использованием.

use core::assert_matches;

/// [Случайное число](https://xkcd.com/221/)
fn get_random_number() -> u32 {
    // выбрано честным броском кубика.
    // гарантированно случайное.
    4
}

fn main() {
    assert_matches!(get_random_number(), 1..=6);
}

Изменения в WebAssembly targets

WebAssembly targets больше не передают линкеру флаг --allow-undefined, поэтому неопределённые символы при линковке теперь вызывают ошибку линкера, а не превращаются в WebAssembly-импорты из модуля "env". Это изменение не позволяет линковать модули, пока не определены все символы, связанные с линковкой, — так ошибки обнаруживаются раньше и предотвращаются случайные проблемы с именованием символов и подобные сбои.

Неопределённые символы, связанные с линковкой, часто указывают на ошибки сборки или неправильную конфигурацию. Если же нужно прежнее поведение, его можно вернуть через RUSTFLAGS=-Clink-arg=--allow-undefined или, изменив исходный код, с помощью #[link(wasm_import_module = "env")] в блоке, определяющем символ.

Об этом изменении ранее сообщалось в блоге, и теперь оно вступает в силу в Rust 1.96.

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

Два security advisory для Cargo

Rust 1.96 содержит исправления двух уязвимостей для пользователей сторонних реестров.

  • CVE-2026-5223 — уязвимость средней степени серьёзности, связанная с распаковкой tarball crate с символическими ссылками.

  • CVE-2026-5222 — уязвимость низкой степени серьёзности, связанная с аутентификацией при нормализованных URL.

Пользователи crates.io не затронуты ни одной из этих уязвимостей.

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

Посмотрите все изменения в Rust, Cargo и Clippy.

Участники релиза 1.96.0

Многие люди объединили усилия, чтобы создать Rust 1.96.0. Без вас это было бы невозможно. Спасибо!