Rust 我怎样才能拥有一个物品可以访问容器的容器?

Rust 我怎样才能拥有一个物品可以访问容器的容器?,rust,Rust,我试图实现一个容器,其中包含一个GUI小部件列表,每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件。例如,当用户单击按钮时,编辑器文本将得到更新 我可以使用装箱的HashMap,但它不能解决问题。实现我所需要的最简单的方法是什么 这是我目前拥有的,它没有编译,但你会明白: use std::collections::HashMap; struct SharedItem<'a> { pub value: String, pub store: &

我试图实现一个容器,其中包含一个GUI小部件列表,每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件。例如,当用户单击按钮时,编辑器文本将得到更新

我可以使用装箱的
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:另一方面,虽然它是安全的,但很容易在某个地方出现引用循环和内存泄漏,这很烦人。