Что означает подтип и дисперсия в Rust
Nomicon - не полностью отшлифованный документ. Прямо сейчас, 5 из 10 последних выпусков в этом репо конкретно касаются подтипов или отклонений, основанных только на их названии. Концепции в Nomicon могут потребовать значительных усилий, но информация, как правило, там.
Прежде всего, посмотрите некоторые начальные абзацы (выделено мной):
Подтипирование в Rust немного отличается от подтипирования в других языках. Это затрудняет приведение простых примеров, что является проблемой, поскольку подтипы, и особенно дисперсию, уже трудно понять должным образом.
Для простоты в этом разделе будет рассмотрено небольшое расширение для языка Rust , которое добавляет новые и более простые отношения подтипов. После определения концепций и проблем в рамках этой более простой системы мы свяжем ее с тем, как на самом деле происходит подтип в Rust.
Затем он показывает код, основанный на особенностях. Повторяя точку зрения, этот код не код Rust больше; черты не образуют подтипы в Rust!
Позже есть эта цитата:
Прежде всего, ссылки на подтипы, основанные на их времени жизни, - это вся точка подтипа в Rust. Единственная причина, по которой у нас есть подтипы, заключается в том, что мы можем передавать долгоживущие вещи там, где ожидаются недолговечные вещи.
Понятие подтипа Rust применимо только к временам жизни .
Что является примером подтипа и дисперсии?
Вариант жизни
Вот пример подтипа и дисперсии времени жизни на работе внутри Box
.
Неудачный случай
fn smaller<'a>(v: Box<&'a i32>) {
bigger(v)
}
fn bigger(v: Box<&'static i32>) {}
error[E0308]: mismatched types
--> src/lib.rs:2:12
|
2 | bigger(v)
| ^ lifetime mismatch
|
= note: expected type `std::boxed::Box<&'static i32>`
found type `std::boxed::Box<&'a i32>`
note: the lifetime 'a as defined on the function body at 1:12...
--> src/lib.rs:1:12
|
1 | fn smaller<'a>(v: Box<&'a i32>) {
| ^^
= note: ...does not necessarily outlive the static lifetime
Рабочий кейс
fn smaller<'a>(v: Box<&'a i32>) {}
fn bigger(v: Box<&'static i32>) {
smaller(v)
}
Инвариантные времена жизни
Вот случай, который работает:
struct S<'a>(&'a i32);
fn smaller<'a>(_v: &S<'a>, _x: &'a i32) {}
fn bigger(v: &S<'static>) {
let x: i32 = 1;
smaller(v, &x);
}
Тот же код со всеми ссылками, измененными на изменяемые ссылки, завершится ошибкой, потому что изменяемые ссылки являются инвариантными:
struct S<'a>(&'a mut i32);
fn smaller<'a>(_v: &mut S<'a>, _x: &'a mut i32) {}
fn bigger(v: &mut S<'static>) {
let mut x: i32 = 1;
smaller(v, &mut x);
}
error[E0597]: `x` does not live long enough
--> src/lib.rs:7:16
|
7 | smaller(v, &mut x);
| -----------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `x` is borrowed for `'static`
8 | }
| - `x` dropped here while still borrowed
Обращение к конкретным точкам
B
явно является «подтипом» A
Это не так.
Box
является ковариантным по своему входу
Это когда ковариация применима только к жизням.
Я не знаю, почему это не работает или почему оно не приводит к принуждению.
Это покрыто Почему Rust не поддерживает вытеснение объекта черты?
Почему они считают Box<T>
ковариантным
Потому что это так, для вещей в Rust, к которым применяется дисперсия.
Смотри также