
'static
функции (замыкания, которые захватывают что-то по ссылке)?В
std
скоро(™) собираются такое добавить: <twitter:m_ou_se>Size: a a a
'static
функции (замыкания, которые захватывают что-то по ссылке)?std
скоро(™) собираются такое добавить: <twitter:m_ou_se>I
and l
very similar and it's wrong.I
and l
especially where there is user input (like about yourself, post texts, etc)let person = get_person();Пока что это работает только с именами, а не произвольными выражениями, но всё равно приятно. Прощайте
// ...
println!("Hello, {person}!"); // captures the local `person`
format!("{name}", name = name);
!*const T
указатели можно дерефать в константных контекстахcopy{,_nonoverlapping}
опять включили debug_assert
'ы[2]Clone
для RSplit<T, P>
больше не требует T: Clone
— Трейт Termiation
теперь реализов для Result<Infallible, E>
, позволяя писать fn main() -> Result<Infallible, ErrorType>
, для програм которые не заканчиваются успешно через выход из main
— Стабилизировали File::options
, замену FileOptions::new
— Стабилизировали {Option,Result}::unwrap_unchecked
— Стабилизировали многие методы Duration
и MaybeUninit
как const fn
— Компилятор теперь будет пытаться применять стабильные методы прежде, чем не стабильные. Это позволит избежать поломок при добавлении в std
методов, пересикающихся по именам с методами из сторонних трейтов.rustdoc
теперь показывает методы из всех Deref
реализаций, рекурсивно (а не только из первой)struct A<T, U: ?Sized + 'static>(T, B<T, U>);
struct B<T, U: ?Sized>(T, U);
fn main() {
let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
// This previously did not work as the last field of `A` also mentions `T`,
// as only `U` changes this is now allowed thanks to this feature.
let _y: &A<[u32; 1], [u32]> = &x;
}
TL;DR: если последнее поле это структура, которая ансайзиться, то теперь и наружняя структура тоже ансайзиться.Unsize
from source to targetconst fn
Полный список изменений: RELEASES.md#version-1580-2022-01-13Trait::method(&value, arg1, arg2)
). Менее известен тот факт, что методы самого типа (inherent methods) перекрывают одноимённые методы трейтов, так что если одному имени отвечают метод типа и сколько угодно методов трейтов, то предпочтение всегда отдаётся методу самого типа и не вызывает неоднозначностей. Этим можно воспользоваться, чтобы иметь возможность в необобщённом контексте вызывать методы трейта, не импортируя сам трейт:trait Trait {
fn method(&mut self, arg: Arg);
}
struct Type {
...
}
impl Trait for Type {
fn method(&mut self, arg: Arg) {
...
}
}
impl Type {
fn method(&mut self, arg: Arg) {
Trait::method(self, arg)
}
}
// где-то в другом месте, где в текущем пространстве имён
// есть Type, но нету Trait:
let mut value = Type::make(...);
value.method(arg);
struct TreeNode<T> {
value: T,
left: Option<Box<Self>>,
right: Option<Box<Self>>,
}
struct Tree<T> {
root: Option<TreeNode<T>>,
}
Однако тут у нас по аллокации на каждый узел, от чего у нас страдает локальность данных и, как следствие, эффективность кеша (не говоря уже о стоимости аллокаций в рантайме). С другой стороны, у нас есть возможность делать дерево произвольной (насколько хватит оперативки, конечно же) высоты. А можем ли мы, отказавшись от произвольной высоты и задавая её предел наперёд, хранить вложенные узлы напрямую, а не через указатель? Как оказалось, да!struct Z;Теперь немного подумаем о том, как это отобразить на древовидную структуру. Каждый узел дерева высотой N + 1 включает в себя узлы высотой N. Узел же дерева с высотой 0 не должен включать в себя данные вообще. Этого можно добиться, сопоставив Z тип с полями ненаселённого типа.
struct S<T>(T);
S<T>
с типом T
, а для Z
с типом never Infallible
, параметризуем узел высотой Height
и параметризуем вложенные узлы <Height as Decrement>::Output
... К сожалению, это не работает: если определить узел таки образом, rustc не понимает, что рекурсия рано или поздно кончается, и жалуется на бесконечную вложенность типа без индирекции. Кажется, нам нужен другой подход.struct Node<T, Next> {
value: T,
left: Next,
right: Next,
}
Тут важно, что поля left
и right
имеют тип Next
, а не Option<Next>
, иначе мы не сможем сделать узел нулевой высоты ненаселённым типом. Собственно, вот как отображение выглядит для Z
:use std::convert::Infallible as Never;
trait Project<T> {
type Projected;
}
impl<T> Project<T> for Z {
type Projected = Node<T, Never>;
}
Итого узел нулевой высоты нельзя сконструировать, как мы и хотели. Лишь немногим сложнее выглядит отображение для S<N>
:impl<T, N> Project<T> for S<N>
where
N: Project<T>,
{
type Projected = Node<T, Option<N::Projected>>;
}
Так как мы не хотим оперировать узлами напрямую (хотя бы потому, что через них затруднительно наложить ограничение на высоту), сделаем обёртку — собственно параметризованное высотой дерево:struct Tree<T, Height: Project<T>> {
repr: Height::Projected,
}
Теперь реализуем парочку вспомогательных методов и попробуем сделать дерево высоты 2 (=S<S<Z>>
):let tree: Tree<i32, S<S<Z>>> = Node {
value: 42,
left: None,
right: Some(Node {
value: 42,
left: None,
right: None
}),
}.into();
Что ж... Оно работает. И даже нормально печатается поле repr
, если добавить #[derive(Debug)]
на Node
. Попробуем теперь поменять тип дерева на дерево с единичной высотой:let tree: Tree<i32, S<Z>> = Node {
...
Компилятор ожидаемо жалуется:error[E0271]: type mismatch resolving `<Z as Project<i32>>::Projected == Node<{integer}, Option<_>>`
--> src/main.rs:181:7
|
181 | }.into();
| ^^^^ expected enum `Option`, found enum `Infallible`
|
= note: expected struct `Node<{integer}, Option<_>>`
found struct `Node<i32, Infallible>`
Не слишком внятно, но цели статически ограничить высоту дерева мы успешно достигли.