Вышла версия Rust 1.83.0! Как всегда, тут только избранные части, а всё остальное в детальных заметках.
▪️В const-контекстах теперь можно использовать
&mut-ссылки, а также &-ссылки на типы с внутренней изменяемостью!const fn inc(x: &mut i32) {
*x += 1;
}
const C: i32 = {
let mut c = 41;
inc(&mut c);
c
};Написание const-кода серьёзно упростилось. Само итоговое значение константы, впрочем, не может быть изменяемой (в том числе через внутреннюю изменяемость) ссылкой.
Также итоговое значение константы теперь может содержать
&-ссылку на static, если в типе нет внутренней изменяемости. static S: i32 = 25;
const C: &i32 = &S;
По понятным причинам итоговое значение константы не может содержать изменяемую (в том числе через внутреннюю изменяемость) ссылку на
static.▪️Как прямое следствие предыдущего пункта — кучу функций можно теперь использовать в const-контексте, включая множество операций над сырыми указателями (в том числе
NonNull) и различные функции для разбиения мутабельных слайсов на части.▪️Также стабилизировали кучу новых вариантов io::ErrorKind. Забавный факт: эти варианты были и раньше и использовались в std, и в теории по ним можно было матчиться, используя реализацию
Display. Ещё забавный факт: стабилизацию всех этих вариантов и ещё некоторых запланировали 23 месяца назад, но первый PR со стабилизацией застопорился из-за некоторых вариантов, которые были слишком специфичны для конкретных операционных систем. Собственно, новый PR со стабилизацией приняли лишь потому, что эти варианты из списка на стабилизацию выкинули.▪️Ещё в число стабилизированных API вошли
hash_map::{Entry, VacantEntry}::insert_entry. Эти методы вставляют переданное значение, но, в отличие от insert, возвращают не мутабельную ссылку на значение, а OccupiedEntry.▪️Одновременные атомарные и неатомарные доступы на чтение из одной локации в памяти одного размера теперь не считаются гонкой данных и потому не являются UB (в C++ — является, поскольку атомарные доступы в C++ происходят через создание atomic_ref, абстрактная машина C++ оперирует типизированной памятью).
▪️Предыдущие версии языка ошибочно считали
#[non_exhaustive]-структуры с ненаселёнными полями населёнными типами вне крейта, в которых они определены. В этой версии это странное поведение исправили. Для пользователей языка это означает, что, например, с вот таким определением:enum Empty {}
#[non_exhaustive]
struct Foo(Empty);следующая функция скомпилируется вне зависимости от того, определена ли она в том же крейте, что и
Foo, или нет:fn eliminate<T>(f: Foo) -> T {
match f {}
}▪️Из забавного: компилятор теперь выдаёт ошибку на атрибут
#[repr(Rust)], применённый на определение, которое не является перечислением, структурой или объединением.