closures - 引用其他闭包的存储闭包

标签 closures rust

我正在尝试创建一个回调系统,其中任何回调都可以包含在另一个回调中,以在调用它之前或之后修改它的行为。此代码有效:

type Closure = Box<Fn(&i32) -> i32>;

fn foo() {
    let add_closure = |closure: Closure| {
        let bar: Closure = Box::new(move |x| {
            println!("{}", x);
            closure(x)
        });
    };

    add_closure(Box::new(|&x| x + 2));
}

fn main() {
    foo()
}

但是一旦我将生命周期边界添加到闭包中,它就不会:

type Closure<'a> = Box<Fn(&'a i32) -> i32>;

fn foo<'a>() {
    let add_closure = |closure: Closure<'a>| {
        let bar: Closure<'a> = Box::new(move |x| {
            println!("{}", x);
            closure(x)
        });
    };

    add_closure(Box::new(|&x| x + 2));
}

fn main() {
    foo()
}

我收到这个错误:

./vec_closure.rs:5:32: 8:11 error: the type `[closure@./vec_closure.rs:5:41: 8:10 closure:Box<core::ops::Fn(&'a i32) -> i32 + 'static>]` does not fulfill the required lifetime [E0477]
./vec_closure.rs:5         let bar: Closure<'a> = Box::new(move |x| {
./vec_closure.rs:6             println!("{}", x);
./vec_closure.rs:7             closure(x)
./vec_closure.rs:8         });
note: type must outlive the static lifetime
error: aborting due to previous error

似乎添加生命周期绑定(bind)会导致 Box 变为 'static,但我不明白为什么会这样或如何避免它。

最佳答案

首先,你需要知道Box<T>有一个隐含的生命周期;如果你要拼写出来,那就是Box<T + 'static> .原因是 Box你想活多久就活多久,所以你存储在里面的东西需要活多久就活多久。只有具有 'static 的类型终身资格。换句话说,这可以防止您装箱仅暂时有效的内容(例如 &'a T 仅对 'a 有效)。

所以 Box<Fn(&'a i32) -> i32>实际上是 Box<(Fn(&'a i32) -> i32) + 'static> .但是,这是一个问题,因为 'a .您可能认为这是在说“闭包需要一个一些生命周期的指针”,但事实并非如此。它表示闭包作为一个整体在某个生命周期内被参数化,因此,仅在生命周期内有效。

换句话说,不是说“这个类型是一个带指针的闭包(对 'a 有效)”,而是说“这个类型(对 'a 有效)是一个带指针的闭包(也适用于 'a )”。

这与隐式 'static 不兼容这是 Box<T> 的一部分类型,所以它不会工作。

实际上想要的是使闭包对任何旧的生命周期都有效,而这只是它的参数是受约束的。您可以使用 Higher-Rank Trait Bounds 来执行此操作,像这样:

type Closure = Box<for<'a> Fn(&'a i32) -> i32>;

现在,不是选择一个特定的生命周期,Closure type 是有效的,这就是说类型本身总是有效的,但是参数的类型受某个任意生命周期的限制。

此时,你可以替换Closure<'a>Closure , 并且有效。

type Closure = Box<for<'a> Fn(&'a i32) -> i32>;

fn foo<'a>() {
    let add_closure = |closure: Closure| {
        let bar: Closure = Box::new(move |x| {
            println!("{}", x);
            closure(x)
        });
    };

    add_closure(Box::new(|&x| x + 2));
}

fn main() {
    foo()
}

关于closures - 引用其他闭包的存储闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33459983/

相关文章:

Javascript 闭包与 Object.createProperty

javascript - JavaScript 中匿名函数中的参数变量

rust - 如何表达闭包的生命周期限制以匹配特征有界生命周期?

error-handling - 使用 xml-rs xml::reader::Error 返回自定义错误

rust - 如何从文件或 URL 创建 Rust Quick XML 阅读器?

javascript - 关闭并让关键字产生意外结果

javascript - 如何在 javascript 中访问当前范围之外的变量?

rust - 将结构的成员传递给 Rust 中相同结构的方法

rust - 将 Rust 中的错误与特征对象生命周期混淆

rust - 将未知类型的 PgRow 值转换为字符串