当使用参数的生命周期作为特征参数时,"预期的关联类型,找到`u32`"

Luk*_*odt 13 rust

我试着编译这段代码(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
    }
}
Run Code Online (Sandbox Code Playgroud)

但遗憾的是,它导致了这个错误:

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`
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么.显然,在这段代码中,<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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以Self::Item::from(0u32)在身体中说出来next().(游乐场)

我认为很明显为什么错误next()消失了:U32Family::from总是把它u32作为参数.硬编码.永不改变.关于这种解决方法的更大问题是:为什么from()方法编译正常?所以from()编译器在某种程度上知道<Self as Family<'a>>::Out永远u32,但如果我尝试相同的next(),莫名其妙的编译器不明白<Self::Item as Family<'s>>::Outu32.现在我更加困惑.

编辑2:首先,我怀疑专业化是问题所在.例如,您可以写:

impl Family<'static> for U32Family {
    type Out = char;
}
Run Code Online (Sandbox Code Playgroud)

当然,编译器会认为u32它并不总是与<Self::Item as Family<'s>>::Out任何一个相同's.但是,我认为这不是问题.

首先,需要使用default关键字标记可以专门化的impl .我没有这样做,所以我应该能够假设相关的类型实际上u32(RFC谈论的东西非常相似).但另外,不允许基于生命期的专业化.

所以到现在为止我倾向于认为这是一个编译器错误.但是我想得到另一个答案!

Kos*_*sta 0

struct U32Family;
...
impl Iterator for Foo {
type Item = U32Family;
Run Code Online (Sandbox Code Playgroud)

因此 next() 必须返回Option<U32Family>,其唯一可能的值是NoneSome(U32Family{})

您可能希望Item = <U32Family as Family<'static>::Out它可以解决此问题,但会产生一些终生问题。(该物品需要终生,因为家庭有一个,但您只接受终生next()