【问题标题】:Conflicting lifetime requirements when storing closure capturing returned value存储闭包捕获返回值时存在冲突的生命周期要求
【发布时间】:2015-03-29 05:12:21
【问题描述】:

编辑:

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

代码可以执行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&lt;RefCell&lt;...&gt;&gt;move ||Fn() 特征一起使用,而不是Shepmaster 建议的FnMut()m,帮助我生成了上述代码的工作版本。 Rust 游戏笔版本here.

【问题讨论】:

  • 我强烈建议您创建一个MCVE 来帮助我们更好地帮助您。我的猜测是,您可以删除许多结构的方法并仍然重现相同的问题。
  • 我会尝试找出一个更短的版本。谢谢。
  • 虽然有些粗略的戳戳似乎表明我可能是错的;-)。我认为您可以删除 T'a(将其替换为 'static)以使其更小。
  • 不会将其静态推送到全局范围吗?我不确定我是否已经完全理解了那一世。我想,需要阅读。 ;)

标签: closures rust


【解决方案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拥有它。然后,我们创建另一个闭包来捕获fby-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
}

【讨论】:

  • 完美理解问题。 :) 我真的觉得我开始更好地理解生命周期的概念了。但是您对如何解决它有什么建议吗?我已经更新了问题。
  • @Emanuel 不是很好,我用了一把相当大的锤子,但我已经更新了。
  • 出色的解释和有效的解决方案。我有很多事情要考虑。我将此问题标记为已解决。谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-22
  • 2023-03-11
  • 1970-01-01
  • 2014-08-11
相关资源
最近更新 更多