存储闭包捕获返回值时的生命周期要求冲突

时间:2015-01-29 20:18:40

标签: closures rust

修改

我正在尝试在函数内创建闭包向量,向向量添加标准闭包,然后从函数返回向量。我收到了关于生命冲突的错误。

代码可以执行here

fn vec_with_closure<'a, T>(f: Box<FnMut(T) + 'a>) -> Vec<Box<FnMut(T) + 'a>>
{
    let mut v = Vec::<Box<FnMut(T)>>::new();
    v.push(Box::new(|&mut: t: T| {
        f(t);
    }));
    v
}

fn main() {
    let v = vec_with_closure(Box::new(|t: usize| {
        println!("{}", t);
    }));
    for c in v.iter_mut() {
        c(10);
    }
}

编辑2:

使用Rc<RefCell<...>>move ||以及Fn()特征而不是Shepmaster建议的FnMut() m,帮助我生成了上述代码的工作版本。 Rust围栏版本here

1 个答案:

答案 0 :(得分:1)

这是我对这个问题的理解,略微缩小了:

fn filter<F>(&mut self, f: F) -> Keeper
    where F: Fn() -> bool + 'static //'
{
    let mut k = Keeper::new();
    self.subscribe(|| {
        if f() { k.publish() }
    });
    k
}

在此方法中,f是一个已按值传递的值,这意味着filter拥有它。然后,我们创建另一个闭包,用于捕获f by-reference 。然后我们尝试在某处保存该闭包,因此闭包中的所有引用都需要比我们结构的生命周期更长(为方便起见,我选择'static。)

但是,f只会持续到方法结束,所以它肯定不会活得足够长。我们需要使闭包拥有f。如果我们可以使用move关键字,但这会导致闭包也在k中移动,那将是理想的,因此我们无法从函数中返回它。

试图解决这个问题导致了这个版本:

fn filter<F>(&mut self, f: F) -> Keeper
    where F: Fn() -> bool + 'static //'
{
    let mut k = Keeper::new();
    let k2 = &mut k;
    self.subscribe(move || {
        if f() { k2.publish() }
    });
    k
}

有一条有用的错误消息:

error: `k` does not live long enough
let k2 = &mut k;
              ^
note: reference must be valid for the static lifetime...
...but borrowed value is only valid for the block

这会导致另一个问题:您尝试在闭包中保留对k的引用,但只要从函数返回k,该引用就会变为无效。当项目按值移动时,它们的地址将会改变,因此引用不再有效。

一种可能的解决方案是使用RcRefCell

fn filter<F>(&mut self, f: F) -> Rc<RefCell<Keeper>>
    where F: Fn() -> bool + 'static //'
{
    let mut k = Rc::new(RefCell::new(Keeper::new()));
    let k2 = k.clone();
    self.subscribe(move || {
        if f() { k2.borrow_mut().publish() }
    });
    k
}