鉴于使用回调将事件传递给库用户的库(例如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。 如何解决这个问题?
答案 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>