【问题标题】:Rust says the function parameter does not live enough, even though proper lifetime have been placedRust 说函数参数的生命周期不够长,即使已经放置了适当的生命周期
【发布时间】:2020-09-30 04:05:15
【问题描述】:

对于背景上下文:我正在创建一个基于观察者/订阅者的全局事件系统(使用单个共享事件系统)。我决定使用FnMut 作为我的回调闭包。位于临时结构Data<'a>impl 的生命周期'a 应该允许方法mut_func() 中的callback 参数与整个Data 结构一样长。因为callback 参数使用F 泛型,它肯定受到生命周期'a 的限制。但是错误仍然出现,指出callback 参数的寿命不够长。

我最初使用Box<T> 作为dyn FnMut(u32) 的容器,但Box<T> 要求回调为'static(因为我将装箱的泛型转换为一个盒子特征对象),在我的场景中是无法实现(为了可读性)。然后我尝试使用Rc<RefCell<T>>,遗憾的是它不支持特征对象。

另外,我对callback 参数使用泛型,因为我希望该函数具有更高的可读性,而不是必须看到Box<T> 包裹着整个无处不在的闭包,因为这事件系统将是我计划的核心部分。我会尽一切努力使“前端”更具可读性和更清晰(除了显着的性能影响)。

注意:这是我的示例程序。如果需要,我可以发布实际程序。

错误:

error[E0597]: `callback` does not live long enough
>  | impl<'a> Data<'a> {  
>  |      -- lifetime `'a` defined here  
>  |     fn mut_func<F: FnMut(u32) -> () + 'a>(&mut self, mut callback: F) {  
>  |         self.o.push(&mut callback as &mut dyn FnMut(u32) -> ());  
>  |         ------------^^^^^^^^^^^^^------------------------------  
>  |         |           |  
>  |         |           borrowed value does not live long enough  
>  |         argument requires that `callback` is borrowed for `'a`  
>  |     }  
>  |     - `callback` dropped here while still borrowed  

例子:

use std::any::Any;
use std::mem;
use std::rc::Rc;
use std::cell::RefCell;

struct Event<'a> {
    obs: Vec<&'a mut dyn FnMut(u32) -> ()>,
}

impl<'a> Event<'a> {
    fn subscriber<F: FnMut(u32) -> () + 'a>(&mut self, mut callback: F) {
        self.o.push(&mut callback as &mut dyn FnMut(u32) -> ());
    }
}

fn main () {
    let mut e = Event {obs: Vec::new()};
    let x = 3;
    e.subscriber(|n| {x+n;});
}

【问题讨论】:

    标签: generics rust closures lifetime trait-objects


    【解决方案1】:

    callback 参数使用F 泛型,它肯定受到生命周期'a 的限制。但是错误仍然出现,指出callback 参数的寿命不够长。

    callback 的寿命足够长,但问题是您没有存储收到的 callback,而是将其存储转换为特征对象 (dyn) trait 对象的数据必须归某物所有。

    我最初使用Box&lt;T&gt; 作为dyn FnMut(u32) 的容器,但Box&lt;T&gt; 要求回调为'static

    不,它没有。这样编译:

    struct Event<'a> {
        obs: Vec<Box<dyn FnMut(u32) -> () + 'a>>,
    }
    
    impl<'a> Event<'a> {
        fn subscriber<F: FnMut(u32) -> () + 'a>(&mut self, callback: F) {
            self.obs.push(Box::new(callback));
        }
    }
    

    然后再进行一项更改,您的示例将编译:在e 之前定义x,以便x 的寿命比e 长:

    fn main() {
        let x = 3;
        let mut e = Event {obs: Vec::new()};
        e.subscriber(|n| {x+n;});
    }
    

    Rust Playground copy

    【讨论】:

    • 好吧,我忘了说Box&lt;T&gt; 要求callback'static,因为我需要将该泛型转换为特征对象。
    • 没关系。其实我不知道你可以直接装箱一个泛型,它会自动成为一个特征对象?
    • @galaticExplorer 它不会因为您将其装箱而自动成为特征对象,而是a type implementing a trait is coercible to the corresponding trait object。因此,由于您请求 一个 trait 对象(通过存储到 Vec&lt;Box&lt;dyn&gt;&gt;),rustc 知道要寻找有效的强制转换,找到一个,一切正常。
    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 2014-12-29
    • 2014-09-10
    • 1970-01-01
    • 2015-12-08
    相关资源
    最近更新 更多