在Rust中,同时在多个子对象上安装可变回调函数的惯用方法是什么?

xoefb8l8  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(135)

我有一个以某种方式操作对象数组的算法,但是调用者需要能够监听由算法触发的某些事件(对象的更新)。
下面是一个简化的示例,说明我正在尝试执行的操作。(Rust playground
这是算法模块:

// Some module containing the algorithm.
// This module doesn't want to know what the caller wants to do in the listener.

trait Listener {
    fn update(&mut self, s: String);
}

struct Object<L: Listener> {
    /* other stuff */
    listener: L,
}

fn do_stuff<L: Listener>(objects: &mut [Object<L>]) {
    // do stuff, which eventually might call the listener of each object any number of times.
    objects[0].listener.update("zero".to_string());
    objects[1].listener.update("one".to_string());
    objects[0].listener.update("zeroes".to_string());
}

调用者将调用do_stuff()do_stuff()以某种方式改变对象数组,并在改变对象时调用每个对象上的侦听器,这个算法模块不需要知道回调被触发时调用者想要做什么。
这是主要模块:

// Main module

// Obviously this can't implement Copy and Clone, because of the mut ref.
struct MyListener<'a>{
    node: &'a mut Vec<String>,
    prefix: &'static str,
}

impl<'a> Listener for MyListener<'a> {
    fn update(&mut self, s: String) {
        self.node.push(format!("{} {}", self.prefix, s));
    }
}

pub fn main() {
    let mut strings = Vec::new();
    let mut objects = vec![
        Object{listener: MyListener{node: &mut strings, prefix: "red"}},
        Object{listener: MyListener{node: &mut strings, prefix: "blue"}},
        Object{listener: MyListener{node: &mut strings, prefix: "green"}},
    ];
    do_stuff(&mut objects);
}

错误:

Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `strings` as mutable more than once at a time
  --> src/main.rs:37:43
   |
35 |       let mut objects = vec![
   |  _______________________-
36 | |         Object{listener: MyListener{node: &mut strings, prefix: "red"}},
   | |                                           ------------ first mutable borrow occurs here
37 | |         Object{listener: MyListener{node: &mut strings, prefix: "blue"}},
   | |                                           ^^^^^^^^^^^^ second mutable borrow occurs here
38 | |         Object{listener: MyListener{node: &mut strings, prefix: "green"}},
39 | |     ];
   | |_____- first borrow later used here

error[E0499]: cannot borrow `strings` as mutable more than once at a time
  --> src/main.rs:38:43
   |
35 |       let mut objects = vec![
   |  _______________________-
36 | |         Object{listener: MyListener{node: &mut strings, prefix: "red"}},
   | |                                           ------------ first mutable borrow occurs here
37 | |         Object{listener: MyListener{node: &mut strings, prefix: "blue"}},
38 | |         Object{listener: MyListener{node: &mut strings, prefix: "green"}},
   | |                                           ^^^^^^^^^^^^ second mutable borrow occurs here
39 | |     ];
   | |_____- first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` due to 2 previous errors

在我的实际代码中,我尝试调用&mut svg::Document上的一个可变函数,而不是更新Vec(从svg板条箱中)向文档添加一些SVG节点,该算法将对象转换为基本形状,每个侦听器获取这些基本形状和当前对象的样式(例如,线宽、颜色),并生成SVG命令并将其添加到svg::Document
上面的代码显然不起作用,因为我多次借用了strings向量,但实际上没有任何方法可以将其拆分,所有这些都需要修改同一个向量。
我也可以让do_stuff返回更新列表,并让调用者稍后应用它们,但这将涉及一堆临时向量。
有没有办法让现在的设计发挥作用?

mspsb9vt

mspsb9vt1#

strings向量 Package 在RefCell中,然后使用共享引用:

use std::cell::RefCell;

struct MyListener<'a> {
    node: &'a RefCell<Vec<String>>,
    prefix: &'static str,
}

impl<'a> Listener for MyListener<'a> {
    fn update(&mut self, s: String) {
        self.node.borrow_mut().push(format!("{} {}", self.prefix, s));
    }
}

pub fn main() {
    let strings = RefCell::new(Vec::new());
    let mut objects = vec![
        Object { listener: MyListener { node: &strings, prefix: "red" }},
        Object { listener: MyListener { node: &strings, prefix: "blue" }},
        Object { listener: MyListener { node: &strings, prefix: "green" }},
    ];
    do_stuff(&mut objects);
}

相关问题