rust“借用的数据转义到方法外”,带闭包

c0vxltue  于 2023-08-05  发布在  其他
关注(0)|答案(2)|浏览(178)

这里的系统是:

  • event:针对不同类型的事件“扩展”的trait
  • window:控制器,负责创建窗口并将其事件进一步传播到队列中
  • 应用范围:整个应用程序的控制器,它创建一个窗口并进行其他操作(现在不重要)。

窗口和应用程序对象必须与程序存在的时间一样长,因为它们本身就是程序。
我需要能够创建一个回调函数(一个闭包或一个方法),并通过“set_event_callback”方法将其传递给窗口结构体,以便在事件发生时调用处理程序。
然而,我面临着一个生命周期的问题,因为下面的代码不会编译错误:

error[E0521]: borrowed data escapes outside of method
  --> src/main.rs:34:9
   |
31 |       pub fn run(&mut self) {
   |                  ---------
   |                  |
   |                  `self` is a reference that is only valid in the method body
   |                  let's call the lifetime of this reference `'1`
...
34 | /         window.set_event_callback(|event| {
35 | |             self.data += 1;
36 | |             false
37 | |         });
   | |          ^
   | |          |
   | |__________`self` escapes the method body here
   |            argument requires that `'1` must outlive `'static`

个字符
我怀疑这可能是因为编译器不知道windowapplication对象的生存期。但我在一周内没有找到解决方案。

**注意:**在run方法(pub fn run(&'static self))中将'static添加到&self会导致另一个错误:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:42:5
   |
42 |     Application::new().run();
   |     ^^^^^^^^^^^^^^^^^^------
   |     |
   |     creates a temporary value which is freed while still in use
   |     argument requires that borrow lasts for `'static`
43 | }
   | - temporary value is freed at the end of this statement

klsxnrf1

klsxnrf11#

我已经修复了你的代码,只是添加了显式的生存期注解。

我已经向编译器保证,callback的生存时间不会超过它所使用的application的唯一引用。

trait Event {}
    
    struct Window<'f> {
        callback: Box<dyn FnMut(&mut dyn Event) -> bool + 'f>,
    }
    
    impl<'f> Window<'f> {
        pub fn new() -> Window<'f> {
            Self {
                callback: Box::new(|_| false),
            }
        }
    
        pub fn set_event_callback<'w, C>(&'w mut self, callback: C)
        where
            C: FnMut(&mut dyn Event) -> bool + 'f,
        {
            self.callback = Box::new(callback);
        }
    }
    
    struct Application {
        data: i32,
    }
    
    impl Application {
        pub fn new() -> Self {
            Self { data: 0 }
        }
    
        pub fn run<'s>(&'s mut self) {
            let mut window = Window::<'s>::new();
    
            window.set_event_callback(|event| {
                self.data += 1;
                false
            });
        }
    }
    
    fn main() {
        let mut app = Application::new();
        app.run();
    }

字符串
但是请记住,一般情况下要避免使用Rust生命周期。它只是更温和的 *C++指针恶魔 * 的化身,处理起来更安全。
然而,它们往往很难写。很少有用例是解决问题的最佳工具。

qcbq4gxm

qcbq4gxm2#

我有第二个解决方案。这一个抽象的一生了。
小开销是:

  • 1堆分配
  • 克隆数据句柄的操作速度较慢
  • 数据操作速度较慢
use std::sync::{
        atomic::{AtomicI32, Ordering},
        Arc,
    };
    
    trait Event {}
    
    struct Window {
        callback: Box<dyn FnMut(&mut dyn Event) -> bool>,
    }
    
    impl Window {
        pub fn new() -> Window {
            Self {
                callback: Box::new(|_| false),
            }
        }
    
        pub fn set_event_callback<C>(&mut self, callback: C)
        where
            C: FnMut(&mut dyn Event) -> bool + 'static,
        {
            self.callback = Box::new(callback);
        }
    }
    
    struct Application {
        data: Arc<AtomicI32>,
    }
    
    impl Application {
        pub fn new() -> Self {
            Self {
                data: Arc::new(AtomicI32::new(0)),
            }
        }
    
        pub fn run(&self) {
            let mut window = Window::new();
    
            let data_handle = Arc::clone(&self.data);
    
            window.set_event_callback(move |_event| {
                data_handle.fetch_add(1, Ordering::SeqCst);
                false
            });
        }
    }
    
    fn main() {
        let app = Application::new();
        app.run();
    }

字符串

相关问题