我try 编写一个闭包,它接收一个闭包(让我们称之为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运算符是为了避免最里面的闭包borrow 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'>表示法指定通用生存期时,如何指定生存期?

推荐答案

这是闭包中的类型推理的一个怪癖.编译器认为闭包接受具有某个特定生存期'a&'a dyn Fn,但实际上您希望它在any个生存期'a(HRTB)中接受&'a dyn Fn.这一事实会导致它出错,原因我不会在这里解释(因为它们又长又复杂).

在夜间,可以按如下方式"修复"错误的生命周期(是的,这很麻烦):

#![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) };

不幸的是,就我所知,没有办法修复这个错误.但你可以通过使用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闭包,并使用一个小帮助器函数来帮助编译器计算出正确的生命周期:

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.

Rust相关问答推荐

为什么拥有的trait对象的相等运算符移动了正确的操作数?

重新导出proc宏导致未解决的extern crate错误""

trait声明中的生命周期参数

返回的future 不是`发送`

获取字符串切片(&;str)上的切片([ia..ib])返回字符串

在UdpSocket上使用sendto时的隐式套接字绑定

如何在 struct 的自定义序列化程序中使用serde序列化_WITH

无法定义名为&new&的关联函数,该函数的第一个参数不是self

在Rust中克隆源自INTO_ITER()的迭代器的成本?

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

如何对一个特征的两个实现进行单元测试?

需要一个有序向量来进行 struct 初始化

在 Rust 中忽略 None 值的正确样式

unwrap 选项类型出现错误:无法移出共享引用后面的*foo

闭包返回类型的生命周期规范

一旦令牌作为文字使用,声明宏不匹配硬编码值?

使用 Rust 从 Raspberry Pi Pico 上的 SPI 读取值

如何展平以下嵌套的 if let 和 if 语句?

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

为什么1..=100返回一个范围而不是一个整数?