我目前正在为 Sway WM 开发一个小型状态栏。该栏由多个实现
Widget
特征的对象组成。
在所有小部件中,时钟有点特别。我不仅想渲染它,还想确保它的渲染及时完成,否则显示的时间通常会有点偏差。由于这个要求,我需要将时钟作为 Widget
和它自己的 Clock
来使用。
我面临的问题是,一旦时钟小部件与其他小部件一起存储在向量中,借用检查器就不允许向量外部存在任何可变引用。这使得无法在主应用程序循环中使用时钟作为
Clock
的实例。
我发现解决这个问题的最干净的方法是通过原始指针和不安全的代码,而不引入运行时开销。我想知道这个问题的其他零运行时开销解决方案。
这是代码的过度简化版本,说明了当前代码的样子:
trait Widget {
fn update_info(&mut self);
fn render(&self);
}
struct NetworkStatus{}
impl Widget for NetworkStatus {
fn update_info(&mut self) {
// query the OS for network information
}
fn render(&self) {
println!("Connected wirelessly");
}
}
struct Clock{}
impl Widget for Clock {
fn update_info(&mut self) {
// query the OS for the current time
}
fn render(&self) {
println!("2024-03-06T19:25:17");
}
}
impl Clock {
fn get_alignment_delay(&mut self) -> std::time::Duration {
return std::time::Duration::new(1, 0);
}
}
fn main() {
let mut netstat = NetworkStatus{};
let mut clock = Clock{};
let clock_ptr = &mut clock as *mut Clock;
let mut widgets: Vec<&mut dyn Widget> = vec![
&mut netstat,
&mut clock,
];
loop {
for w in widgets.iter_mut() {
w.update_info();
}
for w in widgets.iter() {
w.render();
}
std::thread::sleep(unsafe {
(*clock_ptr).get_alignment_delay()
});
}
}
我知道不同的架构可以解决这个问题,但我只是有兴趣学习一些针对这个问题的解决方案,这样我下次看到类似的问题时就知道该怎么做。
Rust 不允许“不受控制”、共享、可变访问。对于您的应用程序,您需要对时钟进行共享、可变的访问,因此您必须选择一种方法来控制它。有很多种可能性,会带来不同的后果。
RefCell
、
Mutex
或 RwLock
中以允许运行时检查突变。fn main() {
let mut netstat = RefCell::new(NetworkStatus{});
let mut clock = RefCell::new(Clock{});
// note these are now `&` references, which may be shared
let mut widgets: Vec<&RefCell<dyn Widget>> = vec![
&netstat,
&clock,
];
loop {
for w in widgets.iter() {
w.borrow_mut().update_info();
}
for w in widgets.iter() {
w.borrow().render();
}
std::thread::sleep(clock.borrow().get_alignment_delay());
}
}
widgets[index_of_the_clock].get_alignment_delay()
的方式访问它。如果用户可以添加和删除多个动画小部件,并且您想检查所有这些小部件的睡眠时间,这可能是有意义的。
RefCell
之类的东西),这样
update()
只需要&self
而不是&mut self
。然后,您可以像上面的代码示例一样与 &
共享对小部件的访问,但不需要包装 RefCell
。 (这可能比第一个选项不太符合人体工程学。)
小部件而不是借用它们。这意味着向量的类型为 Vec<Box<dyn Widget>>
(或者在情况 1 中为
Vec<Box<RefCell<dyn Widget>>>
)。这不会阻止您改变小部件,因为所有权包括改变的能力。