为闭包实现特征会导致绑定/具体的生命周期不匹配

时间:2016-09-06 19:41:20

标签: rust traits lifetime

我想为特定类型的闭包实现特征。这是一个最小的例子(playground):

trait Foo {
    fn foo(&self, x: &u32);
}

impl<F> Foo for F
    where F: Fn(&u32)
{
    fn foo(&self, x: &u32) {
        self(x)
    }
}

fn main() {
    let _: &FnOnce(&u32) = &|x| {};   // works
    let _: &Foo          = &|x| {};   // doesn't work
}

导致此错误:

error: type mismatch resolving `for<'r> <[closure@<anon>:16:29: 16:35] as std::ops::FnOnce<(&'r u32,)>>::Output == ()`:
 expected bound lifetime parameter ,
    found concrete lifetime [--explain E0271]
  --> <anon>:16:28
   |>
16 |>     let _: &Foo          = &|x| {};
   |>                            ^^^^^^^
note: required because of the requirements on the impl of `Foo` for `[closure@<anon>:16:29: 16:35]`
note: required for the cast to the object type `Foo`

error: type mismatch: the type `[closure@<anon>:16:29: 16:35]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r u32,)>` is required (expected concrete lifetime, found bound lifetime parameter ) [--explain E0281]
  --> <anon>:16:28
   |>
16 |>     let _: &Foo          = &|x| {};
   |>                            ^^^^^^^
note: required because of the requirements on the impl of `Foo` for `[closure@<anon>:16:29: 16:35]`
note: required for the cast to the object type `Foo`

我已经尝试将HRTB显式添加到where子句中,如下所示:

where F: for<'a> Fn(&'a u32)

但它没有帮助。我也在impl块上声明了生命周期,如下所示:

impl<'a, F> Foo for F
    where F: Fn(&'a u32) { ... }

但这导致impl块内的生命周期错误。我认为这些错误是正确的,并且无法在impl块上声明生命周期参数。

如何修复此示例?

3 个答案:

答案 0 :(得分:5)

查看错误的这一部分:

  

[...]实现了特征std::ops::Fn<(_,)>,但特征for<'r> std::ops::Fn<(&'r u32,)>是必需的

我认为基本上没有足够的代码来允许正确推断类型。添加显式类型注释允许编译示例:

let _: &Foo          = &|x: &u32| {};

答案 1 :(得分:3)

这是一个部分答案,从一个有趣的实验开始:

trait Foo {
    fn foo(&self, x: &u32);
}

impl<F> Foo for F
    where F: Fn(&u32)
{
    fn foo(&self, x: &u32) {
        self(x)
    }
}

fn main() {
    let f1: &Fn(&u32) = &|_x| {}; 
    let f2: &Foo = &f1;
    // but this fails:
    // let f3: &Foo = &|_x| {};
    f2.foo(&3);
}

Playground

我所做的就是将FnOnce更改为Fn以与特征保持一致,并将第一个闭包分配给类型为&Foo的绑定 - 并且这一个工作。< / p>

这告诉我特征本身很好 - 在制作特征对象时推断闭包的类型是个问题。回到错误,我们被告知闭包实现std::ops::Fn<(_,)>,但for<'r> std::ops::Fn<(&'r u32,)>是必需的。这意味着您尝试的第一件事(将for<'r>...添加到特征中)没有任何效果,因为特征已经需要这个。

此时我被卡住了 - 我认为我不太了解闭包的推理规则,看看为什么会有差异,或者如何让它起作用。我希望有人会来填补它!

答案 2 :(得分:0)

免责声明:我不知道我在做什么。

以下作品:

trait Foo<'a> {
    fn foo(&self, x: &'a u32);
}

impl<'a, F> Foo<'a> for F where F: Fn(&'a u32) {
    fn foo(&self, x: &'a u32) {
        self(x)
    }
}