【问题标题】:Storing a closure with lifetimes in a struct在结构中存储具有生命周期的闭包
【发布时间】:2017-08-03 11:31:24
【问题描述】:

我正在尝试将闭包存储在结构的一部分 Vec 中。闭包是一个工厂函数,它接收 2 个引用作为参数并生成一个 trait 对象,该对象存储闭包作为参数接收的引用。

因此,生成的 trait 对象的生命周期不得超过引用的生命周期。此外,component_registrations 将被多个线程访问,因此被包裹在 Arc<Mutex> 中。

我尝试实现它,但编译器说register_component 函数的泛型参数F 不满足component_registrations 中使用的特征绑定。

这是代码的相关部分:

use std::sync::Mutex;
use std::sync::Arc;

pub mod gl {
    pub struct Gl();
}

pub struct ComponentRegistry<'a> {
    gl: &'a gl::Gl
}

pub trait Component<'a> {
}

pub struct Application {
    component_registrations: Arc<Mutex<Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b>> + Send + 'static>>>>
}

impl Application {
    pub fn new() -> Application {
        Application {
            component_registrations: Arc::new(Mutex::new(vec![]))
        }
    }

    pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
        self.component_registrations.lock().unwrap().push(Box::new(register));
    }
}
error[E0277]: the trait bound `for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not satisfied
  --> src/main.rs:27:59
   |
27 |         self.component_registrations.lock().unwrap().push(Box::new(register));
   |                                                           ^^^^^^^^^^^^^^^^^^ the trait `for<'b> std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not implemented for `F`
   |
   = help: consider adding a `where for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` bound
   = note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`

error[E0271]: type mismatch resolving `for<'b> <F as std::ops::FnOnce<(&'b ComponentRegistry<'b>, &'b gl::Gl)>>::Output == std::boxed::Box<Component<'b>>`
  --> src/main.rs:27:59
   |
27 |         self.component_registrations.lock().unwrap().push(Box::new(register));
   |                                                           ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
   |
note: concrete lifetime that was found is the lifetime 'a as defined on the method body at 26:5
  --> src/main.rs:26:5
   |
26 | /     pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
27 | |         self.component_registrations.lock().unwrap().push(Box::new(register));
28 | |     }
   | |_____^
   = note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`

【问题讨论】:

    标签: rust


    【解决方案1】:

    如果您在定义 component_registrations 结构字段时使用排名较高的生命周期,则您也应该为 F 使用排名较高的生命周期。

    另外,如果你说Box&lt;Component&lt;'b&gt;&gt;,它的真正意思是Box&lt;Component&lt;'b&gt; + 'static&gt;(所以特征对象只能包含拥有的数据)。你真正需要的是Box&lt;Component&lt;'b&gt; + 'b&gt;,这意味着它是一个实现Component&lt;'b&gt; 的特征对象,它还可以包含至少与'b 一样长的借用数据。

    相关部分是

    pub struct Application {
        component_registrations: Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static>>
    }
    
    impl Application {
        pub fn register_component<F>(&mut self, register: F) where F: for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static {
            self.component_registrations.push(Box::new(register));
        }
    }
    

    您可以看到full example。请注意,我从您的示例中删除了 ArcMutex 类型,因为它们不相关。

    【讨论】:

    • 我已经尝试过了,但我无法致电register_component,然后查看here
    • @xomz 我更新了解决方案以应对新的错误。
    猜你喜欢
    • 2014-02-25
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 2019-08-05
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    相关资源
    最近更新 更多