在多个静态闭包中改变相同的数据

时间:2015-05-10 16:44:55

标签: rust

鉴于使用回调将事件传递给库用户的库(例如GUI库),我将如何在程序中进行适当的可变性?例如:

// so I have this `obj` I want to modify when the user clicks buttons
// in the GUI

let same_action = move |_| {
  // modify obj in several ways, e.g. obj.text = "Modified"
  obj.text = "Modified";
}
// --> I had to move `obj` above since `on_click` has a `'static`
// constraint for `F` but that's not really a thing I want to do,
// I want to keep control of `obj` in the outer scope!!!

// --> error because `same_action` does not implement `Fn` since it
// mutates the moved `obj` in it
button1.on_click(same_action);
// --> if the above worked, here we'd have a error because `button1`
// has moved `same_action`
button2.on_click(same_action);
// --> assuming all of the above worked, we'd have a error here about
// unable to use `obj` because it has been moved to same_action
button3.on_click(move |_| obj.text = "Another modifier");

// the library now process the gui and call the callbacks in a loop
// until exit
gui_run();

// --> ..., error cannot use `obj` because it has been moved by
// `same_action`
println!("Final value: {}", obj.text);

请参阅// -->的评论,了解此问题的关键点。

这似乎是一个非常常见的问题,担心Rust中的事件驱动API。 如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

如果您需要共享可变数据,则需要一些容器来确保遵循别名规则,最有可能来自std::cell。对于Copy数据,这是Cell,对于其他类型RefCell。然后闭包可以使用:

  • Cell<TheObject> / Cell<TheObject>
  • TheObject其中一些字段为Cell s和RefCell s。

哪个更好取决于您希望可变性的粒度,以及这是TheObject的所有用户或仅针对此特定闭​​包的常见需求。在第二种情况下,您需要更改TheObject的定义,在第一种情况下,您需要执行以下操作:

let obj = RefCell::new(obj);

let same_action = move |_| {
  obj.borrow_mut().text = "Modified";
}

如果您还无法借助关闭的捕获值,例如由于'static绑定,您可以将RefCell放入Rc }。

此外,您无法将same_action传递给两个按钮,因为无法复制或克隆闭包。一般来说,这是无法完成的,因为它们可能会关闭无法复制或克隆的内容。如果可能的话,将来可能会允许它,因为现在你可以使用宏,函数(必须打开闭包)来解决它,或者只是简单地写两次闭包。如果它很简单。 / p>