将参数的生存期用作受约束的特征参数时,“预期的关联类型,找到'u32”

时间:2018-08-01 17:13:30

标签: 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
    }
}

但是可悲的是,它导致了这个错误:

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。我没有这样做,所以我应该能够假定关联的类型实际上是'sthe RFC talks about something very similar)。但此外,基于生命周期is not allowed的专业化。

因此,到目前为止,我倾向于认为这是编译器错误。但我想再得到一个答案!

2 个答案:

答案 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>,其唯一可能的值为NoneSome(U32Family{})

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