在多个“静态闭包”中改变相同的数据
Mutating the same data in multiple 'static closures
给定一个库(例如 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 的一个非常普遍的问题。
如何绕过它?
如果您需要共享可变数据,则需要一些容器来确保遵循别名规则,很可能来自 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
传递给两个按钮,因为无法复制或克隆闭包。一般来说,这是不可能做到的,因为他们可能会关闭无法复制或克隆的东西。如果可能的话,将来可能会允许这样做,现在您可以使用宏、函数(必须将闭包装箱)或简单地写两次闭包来解决它。
给定一个库(例如 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 的一个非常普遍的问题。 如何绕过它?
如果您需要共享可变数据,则需要一些容器来确保遵循别名规则,很可能来自 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
传递给两个按钮,因为无法复制或克隆闭包。一般来说,这是不可能做到的,因为他们可能会关闭无法复制或克隆的东西。如果可能的话,将来可能会允许这样做,现在您可以使用宏、函数(必须将闭包装箱)或简单地写两次闭包来解决它。