摆脱你最初的代码
pub fn new(context: Arc<Context>) -> Arc<Button> {
let clickable = Clickable::new(context.clone());
let button = Arc::new(Button{
context: context,
clickable: clickable.clone(),
});
let tmp_callback = Box::new(|| {
button.do_stuff();
});
clickable.set_callback(Some(tmp_callback));
button
}
首先,让我们记下您遇到的错误
error[E0373]: closure may outlive the current function, but it borrows `button`, which is owned by the current function
--> src/main.rs:101:37
|
101 | let tmp_callback = Box::new(|| {
| ^^ may outlive borrowed value `button`
102 | button.do_stuff();
| ------ `button` is borrowed here
|
help: to force the closure to take ownership of `button` (and any other referenced variables), use the `move` keyword, as shown:
| let tmp_callback = Box::new(move || {
注意到help
块在底部,你需要使用move
闭包,因为当new
函数结束,则button
堆栈上的变量将超出范围。避免这种情况的唯一方法是将其所有权移至回调本身。这样你就会改变
let tmp_callback = Box::new(|| {
to
let tmp_callback = Box::new(move || {
现在,你会得到第二个错误:
error[E0382]: use of moved value: `button`
--> src/main.rs:107:9
|
102 | let tmp_callback = Box::new(move || {
| ------- value moved (into closure) here
...
107 | button
| ^^^^^^ value used here after move
|
= note: move occurs because `button` has type `std::sync::Arc<Button>`, which does not implement the `Copy` trait
而且这里的错误可能更清楚一点。您正在尝试转移所有权button
值进入回调闭包,但是你also在体内使用它new
当你返回它时,它会被调用,并且你不能有两个不同的东西试图拥有这个值。
希望这个问题的解决方案就是您所猜测的。您必须复印一份can取得所有权。然后你会想要改变
let tmp_callback = Box::new(move || {
button.do_stuff();
to
let button_clone = button.clone();
let tmp_callback = Box::new(move || {
button_clone.do_stuff();
现在你已经创建了一个新的Button
对象,并返回一个Arc
对于对象本身,同时还赋予第二个对象的所有权Arc
回调本身。
Update
鉴于您的评论,这里确实存在循环依赖问题,因为您的Clickable
对象拥有引用的所有权Button
, while Button
拥有引用的所有权Clickable
。解决此问题的最简单方法是第三次更新该代码,从
let button_clone = button.clone();
let tmp_callback = Box::new(move || {
button_clone.do_stuff();
to
let button_weak = Arc::downgrade(&button);
let tmp_callback = Box::new(move || {
if let Some(button) = button_weak.upgrade() {
button.do_stuff();
}
});
so the Clickable
只会持有一个弱引用Button
,如果Button
不再被引用,回调将是无操作。
您可能还想考虑制作clickables
的列表Weak
引用而不是强引用,因此当删除它们引用的项目时,您可以从中删除项目。