rust 如何将闭包中的生命周期与闭包结合起来处理为参数和返回类型?

5cg8jx4n  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(76)

我试过写一个闭包,它接收一个闭包(我们称之为A),这个闭包返回一个接收一个值的闭包,然后将闭包A应用于它。
样品:

let do_some = |f: &dyn Fn(u32) -> u32| move |x: u32| f(x);
let result = do_some(&|v: u32| v * 1111)(7);

字符串
观察结果:

  • 闭包f之所以是&dyn Fn(),是因为这是编译器允许我将一个闭包传递给另一个闭包的唯一方式
  • 最内层闭包上的move操作符是为了避免f被最内层闭包借用

问题:

error: lifetime may not live long enough
 --> src/main.rs:2:44
  |
2 |     let do_some = |f: &dyn Fn(u32) -> u32| move |x: u32| f(x);
  |                       -                  - ^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
  |                       |                  |
  |                       |                  return type of closure `[closure@src/main.rs:2:44: 2:57]` contains a lifetime `'2`
  |                       let's call the lifetime of this reference `'1`


当闭包不允许通过<'a'>表示法指定通用的生存期时,如何指定生存期?

yhived7q

yhived7q1#

这是闭包中类型推断的一个怪癖。编译器认为闭包接受具有特定生存期'a&'a dyn Fn,但实际上您希望它接受&'a dyn Fn * 任何 * 生存期'a(HRTB)。这个事实导致它出错,原因我不会在这里解释(因为它们很长很复杂)。
在夜间,可以按如下方式“修复”错误的生存期(是的,这很麻烦):

#![feature(closure_lifetime_binder, type_alias_impl_trait)]

type RetFn<'a> = impl Fn(u32) -> u32 + 'a;
let do_some = for<'a> |f: &'a dyn Fn(u32) -> u32| -> RetFn<'a> { move |x: u32| f(x) };

字符串
在stable上,不幸的是,据我所知没有办法修复这个错误。但是你可以通过使用Box而不是引用来避免这个问题:

let do_some = |f: Box<dyn Fn(u32) -> u32>| move |x: u32| f(x);
let result = do_some(Box::new(|v: u32| v * 1111))(7);


或者,您可以将 returned 闭 Package 箱,并使用一个小助手函数来帮助编译器计算正确的生命周期:

fn force_hrtb<F: Fn(&dyn Fn(u32) -> u32) -> Box<dyn Fn(u32) -> u32 + '_>>(f: F) -> F {
    f
}
let do_some = force_hrtb(|f| Box::new(move |x: u32| f(x)));
let result = do_some(&|v: u32| v * 1111)(7);


I explained a bit more about the problem here的数据。

相关问题