存储闭包引用其他闭包

0 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()
}
Run Code Online (Sandbox Code Playgroud)

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

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()
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

./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
Run Code Online (Sandbox Code Playgroud)

似乎添加生命周期限制导致Box成为'static,但我不明白为什么这是或如何避免它.

DK.*_*DK. 5

首先,你需要知道它Box<T>有一个隐含的生命周期; 如果你要把它拼出来的话,那就是Box<T + 'static>.这样做的原因是,Box只要你愿意,它就可以存活,所以你存储里面的东西需要你可能需要的时间.只有具有'static生命周期的类型才有资格.换句话说,这可以防止你装箱只是暂时有效的东西(比如只对它&'a T有效'a).

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

换句话说,不是说"这个类型是一个带有指针(对它有效'a)的闭包",你说"这个类型(有效'a)是一个带有指针的闭包(也是有效的) for 'a)".

这与作为类型的'static一部分的隐式不兼容Box<T>,因此它不起作用.

真正想要的是使它成为闭包对任何旧生命有效,而这就是它的论点受到限制.你可以通过使用更高级别的特征界限来实现这一点,如下所示:

type Closure = Box<for<'a> Fn(&'a i32) -> i32>;
Run Code Online (Sandbox Code Playgroud)

现在,不是选择Closure类型有效的特定生命周期,而是说类型本身始终有效,但参数的类型受某些任意生命周期的约束.

在这一点上,你可以替换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()
}
Run Code Online (Sandbox Code Playgroud)