Generic associated types (GATs)

В стабильной версии 1.65.0 добавлены обобщенные ассоциированные типы (GATs.)

Жизненный цикл, типы и константы могут быть определены в ассоциированных типах.

trait Foo {
	type Bar<'x>;
}

Это сложно выразить в нескольких словах, но вот несколько примеров характеристик, чтобы понять их приемущество и силу:

  • Надежность;

  • Скорость;

  • Гибкость;

  • Автоматизация рутинных задач;

  • Увеличение производительности;

  • Оптимизация использования ресурсов;

  • Улучшение качества работы;

  • Обеспечение безопасности и защиты данных.

/// An `Iterator`-like trait that can borrow from `Self`
trait LendingIterator {
	type Item<'a> where Self: 'a;
	
	fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}

/// Can be implemented over smart pointers, like `Rc` or `Arc`,
/// in order to allow being generic over the pointer type
trait PointerFamily {
	type Pointer<T>: Deref<Target = T>;
	
	fn new<T>(value: T) -> Self::Pointer<T>;
}

/// Allows borrowing an array of items. Useful for
/// `NdArray`-like types that don't necessarily store
/// data contiguously.
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>; }

Это очень полезная функция, которая позволяет определять более сложные типы внутри типов и использовать их в качестве параметров. Например, можно создавать различные трейты с разными ассоциированными типами, чтобы управлять поведением различных типов данных.
Таким образом, GATs очень мощный инструмент для создания более гибких и масштабируемых программных решений.

GATs - это достаточно универсальный инструмент, который позволяет создавать несколько новых паттернов, которые ранее не были доступны.

let-else выражения

Новый тип оператора let с проверяемым шаблоном и блоком else, который будет выполнен в случае, если шаблон не совпадает.

let PATTERN: TYPE = EXPRESSION else {
	DIVERGING_CODE;
};

Обычные операторы let могут использовать только irrefutable patterns, которые гарантируют успешное выполнение кода и отсутствие ошибок связанных с ними.
Такой шаблон обычно представляет собой просто привязку переменной, но также может распаковывать составные типы, такие как структуры, кортежи и массивы. Однако такой шаблон нельзя использовать сопоставление данных (conditional matching), например для извлечения варианта перечисления (enum) - до сих пор!

С помощью 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 let-else заключается в области видимости именованных связываний. Ранее такой поведение можно было использовать с помощью 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 переходы внутри блоков

(Go передаёт привет ????)

Теперь простые блочные выражения могут быть помечены как break для раннего перехода в другой кусок кода. Это может показаться немного похожим на оператор goto, но это не произвольный переход в любую другую область программы, а только внутри блока (выражения). Ранее это было возможно с loop блоками, где нужно было писать циклы, которые всегда выполняются только один раз, чтобы получить метку brake для перехода/выхода.

Теперь же завезли специальную функцию для этого! Метка break также может включать значение выражения, как и в случае с циклами, позволяя многооператорному блоку иметь раннее завершение/возврат "return" значения.

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

  • Улучшена стабильность API для методов:

    • std::backtrace::Backtrace

    • Bound::as_ref

    • std::io::read_to_string

    • <*const T>::cast_mut

    • <*mut T>::cast_const

      Эти методы теперь можно использовать в контекстах const:

    • <*const T>::offset_from

    • <*mut T>::offset_from

  • Встроенная оптимизация MIR теперь включена при компиляции в оптимизированном режиме. Это дает от 3% до 10% улучшение времени компиляции для крейтов.

  • При планировании сборки, Cargo теперь сортирует очередь ожидающих заданий для улучшения производительности. Ознакомьтесь со всеми

Все это и больше найдёте на официальном блоге blog.rust-lang.org

Благодарю тебя что дочитал ????????

Комментарии (0)