这里的系统是:
窗口和应用程序对象必须与程序一样存在,因为它们本身就是程序。
我需要能够创建一个回调函数(闭包或方法)并使用“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`
trait Event {}
struct Window {
callback: Box<dyn FnMut(&mut dyn Event) -> bool>
}
impl Window {
pub fn new() -> Self {
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: i32
}
impl Application {
pub fn new() -> Self {
Self {
data: 0
}
}
pub fn run(&mut self) {
let mut window = Window::new();
window.set_event_callback(|event| {
self.data += 1;
false
});
}
}
fn main() {
Application::new().run();
}
我怀疑这可能发生,因为编译器不知道
window
和 application
对象的生命周期。然而,我在一周内找不到解决方案。
注意: 在
'static
方法 &self
中将 run
添加到 (pub fn run(&'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
我有第二个解决方案给你。这个抽象了一生。
小小的开销是:
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();
}
我已经通过添加显式生命周期注释修复了您的代码。
我向编译器保证
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++指针恶魔的更温和的化身,处理起来更安全。
然而它们“通常”很难写。当它们是解决问题的最佳工具时,很少有用例。