我尝试编译此代码(Playground):
trait Family<'a> {
type Out;
}
struct U32Family;
impl<'a> Family<'a> for U32Family {
type Out = u32;
}
trait Iterator {
type Item;
fn next<'s>(&'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>(&'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>(&'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
。但是Rust似乎认为并不总是相同。 为什么?以及如何编译?
一些注意事项:
type Out: for<'a> Family<'a>;
。因此,这不是适合我的解决方法。Family
的生命周期参数,则一切正常。Family<'s>
替换为Family<'static>
,一切正常。编辑:我可以通过添加以下内容来解决此问题:
impl U32Family {
fn from<'a>(v: u32) -> <Self as Family<'a>>::Out {
v
}
}
然后我可以在Self::Item::from(0u32)
的正文中说next()
。 (Playground)
我认为很清楚为什么next()
中的错误消失了:U32Family::from
总是以u32
作为参数。硬编码。永不改变。有关此解决方法的更大问题是:为什么from()
方法可以正常编译?因此,在from()
中,编译器以某种方式知道<Self as Family<'a>>::Out
始终为u32
,但是如果我在next()
中尝试相同的操作,则编译器将以某种方式不了解{{1} }是<Self::Item as Family<'s>>::Out
。现在我更加困惑了。
EDIT2 :首先,我怀疑专业化是问题所在。例如,您可以编写:
u32
那么,当然,对于任何impl Family<'static> for U32Family {
type Out = char;
}
,假设u32
并不总是与<Self::Item as Family<'s>>::Out
相同,那么编译器将是正确的。 但是,我认为这不是问题。
首先,暗示可以专门need to be marked with the default
keyword。我没有这样做,所以我应该能够假定关联的类型实际上是's
(the RFC talks about something very similar)。但此外,基于生命周期is not allowed的专业化。
因此,到目前为止,我倾向于认为这是编译器错误。但我想再得到一个答案!
答案 0 :(得分:1)
我认为问题在于,<Self::Item as Family<'s>>::Out
对所有u32
都是's
是“巧合”。编译器可以针对您想要的任何's
进行证明,但是它甚至无法表达出对所有's
都是正确的概念。
您找到的解决方法是正确的方法:在U32Family
中添加一个方法,将u32
转换为<Self as Family<'a>>::Out
。该方法的主体完全在'a
的范围内,因此编译器可以证明该'a
的转换是类型正确的,因此该方法是类型正确的。然后,在调用现场,您要告诉编译器使用其有关该方法的知识。
答案 1 :(得分:0)
struct U32Family;
...
impl Iterator for Foo {
type Item = U32Family;
因此next()必须返回Option<U32Family>
,其唯一可能的值为None
和Some(U32Family{})
您可能希望Item = <U32Family as Family<'static>::Out
可以解决此问题,但会造成一些终身问题。 (该物品需要一生,因为家族有一个,但是您只接受next()
上的一生)