Я попытался скомпилировать этот код (игровая площадка):
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 говорится о чем-то очень похожем). Но, кроме того, специализация, основанная на сроках жизни , не допускается.
Поэтому я склонен думать, что это ошибка компилятора. Но я хотел бы получить еще один ответ!