如何从具有结构引用的方法返回一个盒装闭包?

时间:2016-11-11 08:33:31

标签: rust closures lifetime

我有一个包含值的结构,我想获得一个对该值进行操作的函数:

struct Returner {
    val: i32,
}

impl<'a> Returner {
    fn get(&'a self) -> Box<Fn(i32) -> i32> {
        Box::new(|x| x + self.val)
    }
}

编译失败:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:7:18
  |
7 |         Box::new(|x| x + self.val)
  |                  ^^^^^^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 5:1...
 --> src/main.rs:5:1
  |
5 | impl<'a> Returner {
  | ^^^^^^^^^^^^^^^^^
  = note: ...so that the types are compatible:
          expected &&Returner
             found &&'a Returner
  = note: but, the lifetime must be valid for the static lifetime...
  = note: ...so that the expression is assignable:
          expected std::boxed::Box<std::ops::Fn(i32) -> i32 + 'static>
             found std::boxed::Box<std::ops::Fn(i32) -> i32>

这是因为闭包借用了self,这对我很好,因为我不想在结构被破坏后使用获得的函数。从我到目前为止收集的内容来看,有两种方法可以实现:

  1. 使用move关键字。我不想使用它,因为它将取得对象的所有权,并希望我在返回此功能后使用它。

  2. 显式指定闭包的生命周期,告诉编译器它与调用它的结构具有相同的生命周期。

  3. 我认为2在我的情况下是正确的方法,但我还没有找到如何指定关闭的生命周期。有没有直接的方法来做到这一点,或者我已经把它弄错了,它与Rust的生命逻辑相矛盾?

2 个答案:

答案 0 :(得分:6)

一般情况下,您可以通过编写Box<Trait + 'a>来指定盒装特征对象的生命周期,类似于其他类型指针后面的特征对象(如果省略,则默认为'static至少在Box)的情况。因此,在这种特定情况下,您需要返回类型Box<(Fn(i32) -> i32) + 'a>

然而,当你这样做时,你会看到另一个关于self生活时间不长的错误。原因是(没有move)闭包将捕获对局部变量self 的引用。解决方案是使用move。这不会移动Returner对象,它会将{{1>} 引用移动到self对象。

总结:

Returner

答案 1 :(得分:1)

如上所述in an existing answer

  1. 添加将self的生命周期与返回值的生命周期相关联的生命周期。
  2. 将对self的引用移动到闭包中。
  3. 从Rust 1.26开始,如果您只返回一个类型,则不再需要来返回一个盒装闭包。相反,您可以使用impl Trait

    impl Returner {
        fn get<'a>(&'a self) -> impl Fn(i32) -> i32 + 'a {
            move |x| x + self.val
        }
    }
    

    另见: