首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >引用其他闭包的存储闭包

引用其他闭包的存储闭包
EN

Stack Overflow用户
提问于 2015-11-01 15:02:21
回答 1查看 195关注 0票数 0

我正在尝试建立一个回调系统,其中任何回调都可以被封装在另一个回调中,以在调用之前或之后修改它的行为。下面的代码可以工作:

代码语言:javascript
复制
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()
}

但是一旦我给闭包添加了生命周期限制,它就不会:

代码语言:javascript
复制
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()
}

我得到了这个错误:

代码语言:javascript
复制
./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

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

EN

回答 1

Stack Overflow用户

发布于 2015-11-01 15:22:18

首先,您需要知道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也有效)”。

这与作为Box<T>类型一部分的隐式'static不兼容,因此它将无法工作。

你真正想要的是让闭包在任何旧的生命周期中都有效,这就是它的参数是受约束的。您可以使用Higher-Rank Trait Bounds来完成此操作,如下所示:

代码语言:javascript
复制
type Closure = Box<for<'a> Fn(&'a i32) -> i32>;

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

在这一点上,您可以用Closure替换Closure<'a>,它可以工作。

代码语言:javascript
复制
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()
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33459983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档