Rust 1.65

Ассоциированные типы теперь можно обобщать, паттерн-матчинг в let
- делать необязательным, а из блоков {}
можно вываливаться раньше времени с помощью break
.
Пройдемся по ченджлогу свежей версии языка.
Обобщенные ассоциированные типы
Или Generic Associated Types, или GAT. Другими словами, ассоциированные типы теперь могут быть обобщены на другие типы, времена жизни (lifetime) и константы:
trait Foo {
type Bar<'x>;
}
Примеры использования GAT:
/// Trait наподобие `Iterator`, который может заимствовать у самого себя
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>;
}
/// Позволяет заимствовать массивы. Удобно для структур,
/// которые могут хранить данные непоследовательно.
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 можно почитать в блоге Rust:
- The push for GATs stabilization - детальный обзор примеров использования.
- Generic associated types to be stable in Rust 1.65 - ограничения реализации GAT.
let-else
Новый синтаксис пытается присвоить значение справа шаблону слева, и если шаблон не подходит, выполняет код в блоке else
:
let PATTERN: TYPE = EXPRESSION else {
DIVERGING_CODE;
};
else
может содержать, например, break
, return
, panic!
.
Прежде распаковывать шаблоны в let
можно было, только если компилятору статически было известно, что шаблоны всегда будет матчиться значению справа. Для let-else
это необязательно.
Пример использования:
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"));
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
};
Прежде разработчикам приходилось писать блок loop
, который выполнялся всегда один раз, чтобы добиться похожего поведения.
Вынос отладочной информации из объектных файлов в Linux
Новые опции компилятора управляют разделением отладочной информации (debuginfo splitting):
-Csplit-debuginfo=unpacked
выносит отладочную информацию в несколько файлов.dwo
-Csplit-debuginfo=packed
выносит отладочную информацию в один пакетный файл.dwp
-Csplit-debuginfo=off
- дефолтное поведение - как прежде оставляет отладочную информацию в секциях.debug_*
объектных файлов и бинарников.
В Rust 1.51 эта функция компилятора стала доступна на macOS, теперь ее добавили для Linux.
Стабилизированные API
std::backtrace::Backtrace
- захват стека выполнения в любой момент времени.Bound::as_ref
std::io::read_to_string
<*const T>::cast_mut
<*mut T>::cast_const
Эти функции теперь доступны в const-контексте:
Полный список изменений доступ в официальном блоге.
Материал подготовлен с ❤️ редакцией Кухни IT.