Я попытался скомпилировать этот код (игровая площадка):
trait Family<'a> {
type Out;
}
struct U32Family;
impl<'a> Family<'a> for U32Family {
type Out = u32;
}
trait Iterator {
type Item;
fn next<'s>(& mut self) -> <Self::Item as Family<'s>>::Out
where
Self::Item: Family<'s>;
}
struct Foo;
impl Iterator for Foo {
type Item = U32Family;
fn next<'s>(& mut self) -> <Self::Item as Family<'s>>::Out
where
Self::Item: Family<'s>,
{
0u32 // <-- in real code, this is somehow calculated
}
}
Но, к сожалению, это приводит к этой ошибке:
error[E0308]: mismatched types
--> src/main.rs:28:9
|
24 | fn next<'s>(& mut self) -> <Self::Item as Family<'s>>::Out
| ------------------------------- expected '<U32Family as Family<'s>>::Out' because of return type
...
28 | 0u32
| ^^^^ expected associated type, found u32
|
= note: expected type '<U32Family as Family<'s>>::Out'
found type 'u32'
Я действительно не понимаю, почему. Очевидно, что в этом фрагменте кода <U32Family as Family<'s>>::Out является именно u32. Но Рур кажется, что это не всегда одно и то же. Зачем? И как я могу скомпилировать его?
Некоторые примечания:
- Есть куча подобных ситуаций, когда происходит аналогичная ошибка, но я думаю, что это отличается от всего, что я видел до сих пор.
- Я не могу использовать
type Out: for<'a> Family<'a>;, Так что это не обходной путь, который работает для меня. - Если я удалю параметр жизни
Family, все будет работать. - Если я заменил
Family<'s>наFamily<'static>в сигнатуре функции, все будет работать.
EDIT: я могу обойти эту проблему, добавив:
impl U32Family {
fn from<'a>(v: u32) -> <Self as Family<'a>>::Out {
v
}
}
Тогда я могу просто сказать Self::Item::from(0u32) в теле next(). (Детская площадка)
Я думаю, что понятно, почему ошибка в next() отсутствует: U32Family::from всегда принимает u32 качестве аргумента. Запрограммированный. Никогда не меняйте. Большой вопрос об этом обходном пути: почему метод from() компилируется отлично? Поэтому in from() компилятор каким-то образом знает, что <Self as Family<'a>>::Out всегда u32, но если я попробую то же самое в next(), то каким-то образом компилятор не понимает, что <Self::Item as Family<'s>>::Out is u32. Теперь я еще более смущен.
EDIT2: во-первых, я подозревал, что проблема специализации. Например, вы можете написать:
impl Family<'static> for U32Family {
type Out = char;
}
Тогда, конечно, компилятор был бы прав, считая, что u32 не всегда совпадает с <Self::Item as Family<'s>>::Out для любого 's. Однако, я думаю, это не проблема.
Прежде всего, импланты, которые могут быть специализированными, должны быть отмечены ключевым словом по default. Я этого не делал, поэтому я мог бы предположить, что связанный тип на самом деле u32 (в RFC говорится о чем-то очень похожем). Но, кроме того, специализация, основанная на сроках жизни , не допускается.
Поэтому я склонен думать, что это ошибка компилятора. Но я хотел бы получить еще один ответ!