我正在学习Rust,并试图创建一个像egui和多线程的管理面板;一个线程更新散列表中的学生结构体,另一个线程运行egui并显示学生信息;这里的问题,我有:
第一个
下面是实现的完整代码:
pub struct Maestro<'a> {
pub students: Arc<HashMap<PathBuf, Mutex<Student>>>,
pub logger: Logger,
pub actual_student: Option<&'a Mutex<Student>>,
// Would like to make like this: pub student: Option<&Student> but cannot get reference to
// Student from mutex's value
}
impl<'a> Maestro<'a> {
pub fn new() -> Self {
let config = load_config();
let watcher = config.watcher;
let students = Arc::new(watcher.init());
let mut students_for_thread = Arc::clone(&students);
std::thread::spawn(move || {
watcher.run(&mut students_for_thread);
});
Maestro {
students,
logger: config.logger,
actual_student: None,
}
}
}
impl<'a> eframe::App for Maestro<'a> {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
for (path, student) in self.students.iter() {
if let Ok(mutex) = student.try_lock() {
ui.horizontal(|ui| {
ui.label(&mutex.name);
match &mutex.bashrc_editable {
true => ui.colored_label(egui::Color32::GREEN, "true"),
false => ui.colored_label(egui::Color32::RED, "false"),
};
if ui.button("See more").clicked() {
if self.students.contains_key(path) {
self.actual_student = Some(self.students.get(path.deref()).unwrap());
// FIXME 10/27/22 ectaclick: lifetime may not live long enough assignment requires that `'1` must outlive `'a`
}
}
});
}
}
});
// Would like to create a 'popup' on the right of the list
if self.actual_student.is_some() {
let student = self.actual_student.unwrap().lock().unwrap();
egui::SidePanel::right("student").show(ctx, |ui| {
ui.label(student.name.as_str());
match student.bashrc_editable {
true => ui.colored_label(Color32::GREEN, "true"),
false => ui.colored_label(Color32::RED, "false"),
}
});
}
std::thread::sleep(Duration::from_millis(100));
}
我试了许多式actual_student
:
Option<Student>
Box<Student>
Option<&Student>
尝试复制值,但actual_student
与Hashmap
中的Student
不同,Hashmap
是由第二个执行绪更新的Student
结构。
但问题还是一样。
1条答案
按热度按时间5f0d552i1#
你会得到一个生存期错误,因为如果这个值从hashmap中删除,你在actual_student中的引用就会无效。
对此问题的直接解决方案是使用
Arc<Mutex<Student>>
而不是Mutex<Student>
使用时只需使用Arc对象的克隆,这是相对轻量级的,因为它不是复制整个对象。
但一般来说,你是在尝试用OOP来思考。一个更好的方法是使用id,例如:
也就是说你得用
每次你都想得到一个实际学生的参考,但这避免了使用Arc,而且可能也会摆脱互斥锁,这甚至更好,因为互斥锁通常是性能打击的来源,有时很难调试。