即使标记了生存期,闭包的寿命也可能超过当前函数

Closure may outlive the current function even if the lifetime is marked

提问人:user2925565 提问时间:3/22/2023 最后编辑:Stargateuruser2925565 更新时间:3/23/2023 访问量:93

问:

fn get_closeures<'a>(x: &'a i64) -> Vec<Box<dyn Fn() + 'a>> {
    let mut ret: Vec<Box<dyn Fn() -> ()>> = Vec::new();
    ret.push(Box::new(|| println!("{}", x + 1)));
    ret.push(Box::new(|| println!("{}", x + 2)));

    ret
}

fn main() {
    let x: i64 = 100;
    {
        let closures = get_closeures(&x);
        for closure in closures {
            closure();
        }
    }
}

操场

导致错误

error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
 --> src/main.rs:3:23
  |
3 |     ret.push(Box::new(|| println!("{}", x + 1)));
  |                       ^^                - `x` is borrowed here
  |                       |
  |                       may outlive borrowed value `x`
  |
note: closure is returned here
 --> src/main.rs:6:5
  |
6 |     ret
  |     ^^^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
  |
3 |     ret.push(Box::new(move || println!("{}", x + 1)));
  |                       ++++

我的问题是,我已经标记了存储的参数的生命周期必须比存储到向量中的闭包长。为什么编译器阻止我借用 x?x

我知道我可以在闭包上添加关键字来修复它。但是如果 x 不是 i64 而是非 Copy 结构,那么这个方法应该不起作用。move

另外,我认为我的代码中没有内存问题,如何说服 rust 编译器相信它?

Rust Closures Lifetime 借用检查器

评论

0赞 Stargateur 3/23/2023
如果没有移动闭包,将引用借用到 X,因此使用 Move,您可以复制引用,现在就可以了,因为此引用的生存期是您想要的,与链接到函数范围的双引用生存期相反。&&i64&i64

答:

2赞 cafce25 3/22/2023 #1

问题在于,如果没有编译器的建议,本地引用就会被引用,并且只有该引用存储在闭包中。但确实在最后被释放了,所以参考现在悬而未决。要修复它,您可以简单地应用编译器的建议,在每个闭包前面添加。movexxget_closuresmove

移动不会复制引用后面的内容,而是复制引用本身,这正是您想要的。T

评论

0赞 Jonas Fassbender 3/22/2023
下面是一个不可复制类型的示例,说明您的描述
1赞 Jmb 3/22/2023 #2

注意它不是类型,而是类型,即引用 。即使基础类型不是,也始终如此。例:xi64&i64i64xCopy

fn get_closeures<'a>(x: &'a str) -> Vec<Box<dyn Fn() + 'a>> {
    let mut ret: Vec<Box<dyn Fn() -> ()>> = Vec::new();
    ret.push(Box::new(move || println!("{}", x)));
    ret.push(Box::new(move || println!("{}", x)));

    ret
}

fn main() {
    let x: String = "azerty".to_string();
    {
        let closures = get_closeures(&x);
        for closure in closures {
            closure();
        }
    }
}

操场

0赞 Kaplan 3/23/2023 #3

您可以分别为每个闭包提供参数:&x

fn get_closures() -> Vec<fn(&i64)> {
    let mut ret: Vec<fn(&i64)> = vec![];
    ret.push(|x| println!("{}", x + 1));
    ret.push(|x| println!("{}", x + 2));

    ret
}

操场