"Ожидаемый связанный тип, найденный" u32 ", когда используется время жизни параметра как параметр параметра, в котором
Я попытался скомпилировать этот код (игровая площадка):
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 говорится о чем-то очень похожем). Но, кроме того, специализация, основанная на сроках жизни , не допускается.
Поэтому я склонен думать, что это ошибка компилятора. Но я хотел бы получить еще один ответ!
Ответы
Ответ 1
struct U32Family;
...
impl Iterator for Foo {
type Item = U32Family;
Поэтому next() должен возвращать Option<U32Family>
, единственными возможными значениями которой являются None
и Some(U32Family{})
Вероятно, вам понадобится Item = <U32Family as Family<'static>::Out
который исправляет эту проблему, но создает некоторые проблемы с продолжительностью жизни. (Элемент нуждается в жизни, потому что у семьи есть одно, но вы принимаете только жизнь на next()
)
Ответ 2
Я думаю, что проблема в том, что это "совпадение", что <Self::Item as Family<'s>>::Out
является u32
для всех 's
. Компилятор может доказать это для любого 's
вы хотите, но он не может даже выразить концепцию, что это верно для всех 's
.
U32Family
который вы нашли, - это правильный подход: добавьте метод U32Family
который преобразует u32
в <Self as Family<'a>>::Out
. Тело метода полностью находится в области 'a
, поэтому компилятор может доказать, что преобразование корректно для текста 'a
, и поэтому метод верен. Затем, на сайте вызова, вы говорите компилятору, чтобы использовать его знания о методе.