我正在使用 ImGui Rust 绑定,我有一个大问题:我需要从另一个线程访问窗口的“系统”变量:这个变量授予对几个函数的控制权,例如更改窗口大小。我需要在.build(ui, || { })
块中访问这个变量。此代码取自(但已缩短)的示例:https ://github.com/Gekkio/imgui-rs/blob/master/imgui-examples/examples/hello_world.rs
use imgui::*;
mod support;
fn main() {
let system: support::System = support::init(file!());
system.main_loop(move |_, ui| {
Window::new(im_str!("Hello world"))
.size([300.0, 110.0], Condition::FirstUseEver)
.build(ui, || {
// Do stuff with the UI here.
});
});
}
这是一个问题,因为事件循环函数(即 .build() 函数中的 lambda)必须使用“移动”来传递所有变量的所有权,因此它们本质上需要静态生命周期。
我遇到过几篇几乎有同样问题的人的帖子,但我的数据是非静态的,不可复制的。这就是头痛发生的地方。
因为我也需要一个全局状态,所以最好将此变量包装在一个结构中。我设法使结构可以毫无问题地传递给线程,但“系统”变量仍然拒绝工作。
以下是我尝试过的一些场景示例:
struct State {
system: Option<support::System>
}
fn main() {
let state = Arc::new(State {
system: Some(support::init(file!()))
});
ERROR -> state.system.unwrap().main_loop(move |x: &mut bool, ui: &mut Ui| {});
}
这不起作用,原因如下:
Arc
由于 value 具有 typestd::option::Option<support::System>
,它没有实现Copy
traitrustc(E0507) main.rs(31, 5) 导致无法移出move 发生:考虑借用Option
的内容
借款是行不通的,所以这肯定很烦人。然后我们只需在结构中存储对support::System的引用,这样就可以解决问题,对吧?
struct State<'a> {
system: Option<&'a support::System>
}
fn main() {
let system = support::init(file!());
let state = Arc::new(State {
ERROR -> system: Some(&system)
});
}
这不起作用,因为 Rust 编译器认为数据的寿命不够长(我知道它会,但编译器无法正确确定)
system
借来的价值不够长 生存时间不够长rustc(E0597) main.rs(59, 1):system
在仍然借用的时候丢到这里 main.rs(25, 17): 参数要求system
借用'static
好吧,这听起来很合理。然后只需使用Box<>将其分配到堆上并忘记整个问题。
struct State {
system: Box<support::System>
}
fn main() {
let state = Arc::new(State {
system: Box::new(support::init(file!()))
});
let state1 = state.clone();
let system1 = &state1.system;
ERROR -> system1.main_loop(move |x: &mut bool, ui: &mut Ui| {
Window::new(im_str!("Main"))
.flags(WindowFlags::NO_DECORATION | WindowFlags::NO_RESIZE)
.position([0f32, 0f32], Condition::Always)
.build(ui, || {
let state = state.clone();
THIS WORKS! -> let system = &state.system;
// Do stuff with the 'system' variable.
});
});
}
这会导致类型稍微复杂一些的错误:
cannot move out
**system1
which is behind a shared reference move 因为**system1
有类型support::System
,它没有实现Copy
traitrustc(E0507)
什么?我正在尝试访问参考,我不想复制任何内容。
我没主意了。我在 C++ 中有几乎完全相同的代码,并且可以毫无问题地工作,因为 C++ 不关心变量所有权:您可以随意传递“状态”指针。
我还想补充一点,我通过将“状态”包装在Arc<Mutex<>>中尝试了相同的Arc<>场景。它会导致示例触发的相同错误之一。我还尝试使用该结构的静态版本,但这会产生它不可变的问题,并且我相信它会引发相同的所有权错误。
我有一种感觉,这很容易解决,但它确实需要一些(高级)Rust 借用机制的经验。我是 Rust 新手(不到一周的爱好经验),我可以掌握很多概念,但我本质上需要避免这里的所有权机制,因为数据必须是全局共享的。
我希望有经验的 Rustacean 知道解决这个问题!提前非常感谢。