Rust 我怎样才能拥有一个物品可以访问容器的容器?
我试图实现一个容器,其中包含一个GUI小部件列表,每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件。例如,当用户单击按钮时,编辑器文本将得到更新 我可以使用装箱的Rust 我怎样才能拥有一个物品可以访问容器的容器?,rust,Rust,我试图实现一个容器,其中包含一个GUI小部件列表,每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件。例如,当用户单击按钮时,编辑器文本将得到更新 我可以使用装箱的HashMap,但它不能解决问题。实现我所需要的最简单的方法是什么 这是我目前拥有的,它没有编译,但你会明白: use std::collections::HashMap; struct SharedItem<'a> { pub value: String, pub store: &
HashMap
,但它不能解决问题。实现我所需要的最简单的方法是什么
这是我目前拥有的,它没有编译,但你会明白:
use std::collections::HashMap;
struct SharedItem<'a> {
pub value: String,
pub store: &'a HashMap<String, SharedItem<'a>>,
}
fn trigger_button(button: &SharedItem) {
// use case where SharedItem has to be mutable
let mut editor = button.store.get(&"editor".to_string()).unwrap();
editor.value = "value inserted by button".to_string();
}
fn main() {
// map shared items by their name
let mut shared_store: HashMap<String, SharedItem> = HashMap::new();
// create components
let editor = SharedItem {
value: "editable content".to_string(),
store: &shared_store,
};
let button = SharedItem {
value: "button".to_string(),
store: &shared_store,
};
shared_store.insert("button".to_string(), button);
shared_store.insert("editor".to_string(), editor);
// now update the editor by triggering button
trigger_button(shared_store.get(&"button".to_string()).unwrap());
}
使用std::collections::HashMap;
结构共享数据项
这是必需的,因为小部件可能需要在某些事件上修改其他小部件。例如:用户单击按钮,编辑器文本将得到更新
仅仅因为这是大多数GUI在OO语言中的操作方式,并不意味着必须这样做
在这种特定情况下,一个简单的解决方案是:
将编辑器框的ID存储为小部件ID
将事件发布到某个事件队列中,指示要执行的更新和要执行更新的小部件(通过ID)
因此,在任何时间点上,系统中最多存在一个小部件上的可变句柄,这可以避免别名并使Rust满意
注意:这个答案假设您不需要来自编辑器小部件的同步响应,如果您这样做并使用这样的系统,您将陷入回调地狱
我怎样才能拥有一个物品可以访问容器的容器
你。你可以这样做
然而,你仍然可以用不同的方式来解决你的问题
每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件
如果它适合您的问题领域,则只需在单向数据流中发布事件就更为简洁:
// Create meaningful events with data pertinent to those events.
enum Event {
UpdateText,
Click,
}
struct Events(Vec<Event>);
impl Events {
fn push(&mut self, event: Event) { self.0.push(event) }
}
trait Widget {
fn event_happened(&mut self, event: &Event, triggered_events: &mut Events);
fn draw(&self);
}
struct Widgets(Vec<Box<Widget>>);
struct TextField(String);
impl Widget for TextField {
fn event_happened(&mut self, event: &Event, _: &mut Events) {
match *event {
Event::UpdateText => self.0.push_str("event"),
_ => (),
}
}
fn draw(&self) {
println!("Drawing text: {}", self.0);
}
}
struct Button;
impl Widget for Button {
fn event_happened(&mut self, event: &Event, triggered_events: &mut Events) {
match *event {
Event::Click => triggered_events.push(Event::UpdateText),
_ => (),
}
}
fn draw(&self) {
println!("Drawing button");
}
}
fn main() {
let mut events = Events(vec![]);
let mut widgets = Widgets(vec![
Box::new(TextField(String::new())),
Box::new(Button),
]);
// This would probably loop forever until a shutdown event was posted
for i in 0..10 {
for widget in &widgets.0 {
widget.draw();
}
// Fake a click at some point
if i == 0 {
events.push(Event::Click);
}
let mut next_events = Events(vec![]);
for event in &events.0 {
for widget in &mut widgets.0 {
widget.event_happened(event, &mut next_events);
}
}
events = next_events;
}
}
//使用与这些事件相关的数据创建有意义的事件。
枚举事件{
UpdateText,
点击
}
结构事件(Vec);
impl事件{
fn推送(&mutself,event:event){self.0.push(event)}
}
特征部件{
fn事件发生(&mut self,事件:&event,触发事件:&mut events);
fn绘制(和自绘制);
}
结构小部件(Vec);
结构文本字段(字符串);
TextField的impl小部件{
fn事件发生(&mut self、事件:&event、&mut Events){
比赛*活动{
Event::UpdateText=>self.0.push_str(“事件”),
_ => (),
}
}
fn绘制(和自绘制){
println!(“绘图文本:{},self.0);
}
}
结构按钮;
按钮的impl小部件{
fn事件\u已发生(&mut self,事件:&event,触发的\u事件:&mut events){
比赛*活动{
Event::Click=>triggered_events.push(Event::UpdateText),
_ => (),
}
}
fn绘制(和自绘制){
println!(“绘图按钮”);
}
}
fn main(){
让mut events=events(vec![]);
让mut widgets=widgets(vec[
Box::new(TextField(String::new()),
框::新(按钮),
]);
//这可能会一直循环,直到发布关闭事件
因为我在0..10{
用于&widgets.0中的小部件{
widget.draw();
}
//在某个点假装点击
如果i==0{
推送(事件::单击);
}
让mut next_events=events(vec![]);
用于事件中的事件(&events.0){
用于&mut小部件中的小部件。0{
事件发生(事件和多个下一个事件);
}
}
事件=下一个事件;
}
}
明确地说,这就是我们所建议的(没有目标ID);我刚刚打了一个例子,所以我想发布它。^ ^。这将是@Shepmaster的副本是的,这是同一个问题的变体,但它没有解决方案,我想知道如何解决它。主要要求是能够从存储器中的项目访问存储器结构。实际上更接近。特别是因为它回答了这个问题:使用引用计数boxes@ker,这实际上非常接近我需要的:)如果我让它工作,我会添加一个答案,除非其他人回答:)这将是比违背生锈的内存安全性更好的方法。从面向对象的背景中改变你的思维方式并不是那么容易。。我会接受这个答案。谢谢你的努力!与生锈的内存安全相反-很明显,使用Rc
并没有什么不安全的地方,它只是将强制执行内存安全从编译时推迟到运行时。@Shepmaster:另一方面,虽然它是安全的,但很容易在某个地方出现引用循环和内存泄漏,这很烦人。