Rust 1.98.0 вышел 20 августа 2026 года и добавил в стабильную ветку новые algebraic_* методы для f32 и f64, позволяющие компилятору свободнее оптимизировать вычисления с плавающей точкой. Релиз также вводит NumBuffer и format_into для быстрого преобразования целых чисел в строки, расширяет стандартную библиотеку и усиливает ряд проверок совместимости.

Algebraic-операции дают компилятору больше свободы при работе с float
Главное изменение Rust 1.98 связано с новыми методами algebraic_add, algebraic_sub, algebraic_mul, algebraic_div и algebraic_rem для типов f32 и f64. Они позволяют разработчику явно указать, что конкретное вычисление допускает преобразования на основе обычных алгебраических правил, даже если такие преобразования могут менять точный результат вычислений в формате IEEE 754.
Обычные операции с плавающей точкой в Rust сохраняют строгую семантику порядка вычислений. Например, выражение:
let x = ((a + b) + c) + d;не должно произвольно превращаться компилятором в:
let x = (a + c) + (b + d);Для вещественных чисел такие выражения математически эквивалентны, но для конечной двоичной точности f32 и f64 результаты могут отличаться из-за округления. Именно поэтому обычная арифметика Rust ограничивает часть агрессивных оптимизаций.
С Rust 1.98 разработчик может явно разрешить подобные преобразования:
let x = a
.algebraic_add(b)
.algebraic_add(c)
.algebraic_add(d);После этого компилятор получает право перегруппировывать вычисления, сокращать критический путь, объединять операции и в ряде случаев лучше использовать SIMD-векторизацию.
По описанию команды Rust, набор разрешённых оптимизаций специально не фиксируется. Поведение может напоминать отдельные эффекты -ffast-math в других компиляторах, но речь не идёт о глобальном переключателе для всей программы: разработчик применяет новые методы только в тех местах, где готов принять ослабление численной воспроизводимости.
Официальная документация отдельно предупреждает, что при использовании algebraic-операций:
- компилятор может менять порядок вычислений;
- деление может преобразовываться в умножение на обратное значение;
- поведение
NaN, бесконечностей и-0.0может отличаться от ожидаемого при строгой арифметике; - точная погрешность результата не гарантируется;
- одинаковые исходные значения не обязаны всегда давать побитно идентичный результат;
- операции при этом не создают undefined behavior.
Практически это делает новые методы интересными для численных циклов, обработки сигналов, графики, физических расчётов, машинного обучения и других задач, где скорость важнее строгой воспроизводимости каждого бита результата.
Для финансовых вычислений, криптографии, тестов с точным сравнением значений и алгоритмов, где последовательность округлений является частью логики, обычные +, -, *, / и % остаются более безопасным выбором.
Официальное объявление Rust 1.98.0
NumBuffer и format_into сокращают накладные расходы при преобразовании чисел
Второе заметное изменение Rust 1.98 — стабилизация core::fmt::NumBuffer и метода format_into для примитивных целочисленных типов.
NumBuffer<T> представляет собой небольшой буфер, размер которого достаточен для хранения десятичного представления любого значения соответствующего целочисленного типа. Метод format_into записывает число непосредственно в этот буфер и возвращает &str, заимствованный из него.
Пример для u32:
use core::fmt::NumBuffer;
let mut buf = NumBuffer::new();
let value = 1972u32;
let text = value.format_into(&mut buf);
assert_eq!(text, "1972");Буфер можно использовать повторно:
use core::fmt::NumBuffer;
let mut buf = NumBuffer::new();
assert_eq!(10u64.format_into(&mut buf), "10");
assert_eq!(42u64.format_into(&mut buf), "42");
assert_eq!(u64::MAX.format_into(&mut buf), u64::MAX.to_string());В отличие от универсальной инфраструктуры форматирования через write!, новый API позволяет избежать части динамической диспетчеризации и связанных с ней накладных расходов. Команда Rust указывает, что в тестах format_into показывает производительность, сопоставимую с популярным crate itoa.
Это не означает автоматического исчезновения сторонних библиотек форматирования. Они могут предлагать дополнительные возможности или уже быть глубоко встроены в существующие проекты. Но для кода, которому требуется только быстро преобразовывать целые числа в десятичный текст, стандартная библиотека теперь закрывает гораздо больше сценариев без внешней зависимости.
Такая оптимизация полезна прежде всего в:
- логгерах;
- сериализаторах;
- HTTP- и сетевых библиотеках;
- генераторах текстовых протоколов;
- системах телеметрии;
- коде с большим количеством числового форматирования.
Стандартная библиотека получила новые стабильные API
Rust 1.98 расширяет стабильную стандартную библиотеку сразу несколькими группами методов.
Среди наиболее заметных:
| API | Назначение |
str::substr_range | Получение диапазона байтов, соответствующего подстроке |
[T]::subslice_range | Определение диапазона исходного среза для subslice |
core::fmt::NumBuffer | Буфер для десятичного форматирования целых чисел |
<integer>::format_into | Форматирование целого числа в NumBuffer |
f32/f64::algebraic_* | Арифметика с разрешёнными алгебраическими оптимизациями |
NonZero<integer>::from_str_radix | Парсинг NonZero из строки с указанным основанием |
String::from_utf16le / from_utf16be | Создание строки из UTF-16 с заданным порядком байтов |
[T]::strip_circumfix | Удаление заданных элементов одновременно с начала и конца |
str::strip_circumfix | Аналогичная операция для строк |
Atomic<T>::from_mut | Работа с атомарным представлением изменяемого значения |
Atomic<T>::get_mut_slice | Получение изменяемого среза из атомарного среза |
Atomic<T>::from_mut_slice | Представление изменяемого среза как среза атомарных значений |
Появление String::from_utf16le, String::from_utf16be и их lossy-вариантов особенно удобно для кода, который работает с бинарными форматами, Windows-данными, сетевыми протоколами или файлами, где порядок байтов UTF-16 известен заранее.
Методы str::substr_range и [T]::subslice_range упрощают обратную задачу: определить, где именно заимствованный фрагмент расположен внутри исходной строки или среза. Ранее для подобных операций разработчики часто вычисляли смещения вручную через указатели или вспомогательные функции.
ManuallyDrop и Box получили стабильную гарантию поведения
Rust 1.98 также закрепляет в документации исправление взаимодействия ManuallyDrop и Box.
До Rust 1.96 следующий сценарий считался undefined behavior:
let mut x = ManuallyDrop::new(Box::new(1));
unsafe { ManuallyDrop::drop(&mut x) };
let x = x;Причина заключалась в том, что после освобождения Box его последующее перемещение считалось недопустимым, а это правило распространялось и на ManuallyDrop<Box<_>>.
В Rust 1.96 поведение компилятора было исправлено. В Rust 1.98 команда проекта оформила это как стабильную гарантию в документации: перемещение ManuallyDrop<Box<_>> после ручного уничтожения содержащегося Box больше не рассматривается как undefined behavior только из-за самого факта такого перемещения.
Изменение особенно значимо для авторов низкоуровневых контейнеров, FFI-обвязок, unsafe-библиотек и собственного кода управления ресурсами. Для обычного прикладного Rust оно почти незаметно.
Новые проверки могут выявить проблемный низкоуровневый код
Rust 1.98 добавляет два новых lint, связанных с определениями runtime-символов.
invalid_runtime_symbol_definitions включён в режиме deny-by-default, а suspicious_runtime_symbol_definitions — warn-by-default. На первом этапе проверки ориентированы прежде всего на символы уровня core, включая функции наподобие memcmp, memset и strlen.
Цель — раньше обнаруживать опасные или некорректные определения символов, которые могут конфликтовать с ожиданиями компилятора и runtime-среды. В будущих версиях Rust область действия этих проверок планируется расширять.
Дополнительно появился warn-by-default lint c_void_returns, который проверяет использование core::ffi::c_void как возвращаемого типа.
Для большинства приложений эти изменения не потребуют правок. Зато разработчикам embedded-систем, собственных runtime, FFI-слоёв и no_std-окружений после обновления стоит внимательно посмотреть на новые предупреждения и ошибки компилятора.
Изменения платформенной поддержки
Rust 1.98 меняет статус нескольких target-платформ.
В Tier 2 переведены:
thumbv7a-none-eabi;thumbv7a-none-eabihf;thumbv7r-none-eabi;thumbv7r-none-eabihf;thumbv8r-none-eabihf.
Это улучшает официальный уровень поддержки ряда ARM-целей, актуальных для embedded-разработки.
Одновременно добавлены новые Tier 3 targets:
powerpc64-unknown-linux-gnuelfv2;aarch64-unknown-linux-pauthtest.
Tier 2 означает более высокий уровень регулярного тестирования и поддержки со стороны проекта, тогда как Tier 3 в первую очередь фиксирует возможность сборки и наличие конфигурации target без тех же гарантий CI.
Совместимость — на что обратить внимание после обновления
Rust 1.98 содержит несколько изменений, способных проявиться в старом или нестандартном коде.
Среди них:
- более строгая обработка неоднозначных импортов;
- часть случаев
ambiguous_glob_importsтеперь превращается из lint в ошибку; - ужесточена проверка
repr(transparent); - исправлена проверка равенства размеров при
transmute()для некоторых комбинацийrepr; std::env::VarsиVarsOsбольше не получают некорректные реализацииSend/Sync;- на Windows деструкторы thread-local объектов переведены на Fiber Local Storage;
- в Emscripten теперь безусловно используется WASM exception handling ABI;
unsafe_codelint более последовательно срабатывает для unsafe-атрибутов;- rustfmt теперь обнаруживает модули, объявленные через
cfg_select!, поэтому после форматирования может затрагиваться больше файлов.
Большинство этих изменений исправляет ранее допускавшиеся пограничные или потенциально некорректные конструкции. Обычные приложения, использующие безопасный Rust и типичный набор crates, с высокой вероятностью обновятся без изменений исходного кода.
Библиотекам с большим количеством unsafe, собственными layout-гарантиями, сложными импортами, FFI и платформенно-зависимым кодом желательно прогнать полный CI до обновления минимальной поддерживаемой версии Rust.
Полные release notes Rust 1.98.0
Cargo 1.98 в основном исправляет регрессии и готовит будущие функции
В стабильной части Cargo 1.98 нет крупной новой пользовательской функции масштаба algebraic_* из стандартной библиотеки. Основное заметное исправление касается Windows: Cargo теперь удаляет завершающий carriage return из токенов, полученных через credential provider cargo:token-from-stdout.
Регрессия появилась в Cargo 1.96 и могла приводить к ошибке failed to parse header value при работе с токенами в Windows-окружении.
В nightly-части одновременно продолжается подготовка нескольких будущих возможностей, включая минимальный возраст публикации зависимости при разрешении версий, MSRV-aware diagnostics и JSON-вывод документации через cargo doc. Эти функции в Rust 1.98 остаются нестабильными и не должны восприниматься как часть стабильного интерфейса релиза.
Rust 1.98 — кому стоит обновляться
Rust 1.98 — обычный стабильный релиз с заметными улучшениями стандартной библиотеки, а не экстренное обновление безопасности. Для большинства проектов переход можно проводить в штатном цикле после выполнения тестов и CI.
Наибольший практический интерес релиз представляет для трёх групп разработчиков.
Первая — авторы производительного численного кода. algebraic_* даёт возможность локально разрешить более агрессивные оптимизации floating-point вычислений, не переводя всю программу на ослабленную численную модель.
Вторая — разработчики библиотек сериализации, логирования, протоколов и инфраструктурного ПО. NumBuffer и format_into позволяют выполнять распространённую операцию преобразования целых чисел в текст средствами стандартной библиотеки с низкими накладными расходами.
Третья — авторы системного, embedded- и unsafe-кода. Новые lint, изменения repr(transparent), transmute(), runtime-символов и платформенной поддержки могут выявить конструкции, которые раньше компилировались, но находились за пределами желательной или корректной семантики.
Обновить установленный stable toolchain можно стандартной командой:
rustup update stableДля приложений, где важна точная воспроизводимость вычислений с плавающей точкой, сами новые algebraic_* методы применять автоматически не стоит. Они являются явным выбором разработчика в пользу дополнительной свободы оптимизатора и потенциальной производительности ценой более слабых гарантий численного результата.