如何将具有捕获的可变变量的回调视为正常的可变借用? [英] How can callbacks with captured mutable variables be treated like normal mutable borrows?

查看:18
本文介绍了如何将具有捕获的可变变量的回调视为正常的可变借用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Foo 可以使用方法 .modify() 进行修改:

Foo can be modified using the method .modify():

struct Foo;
impl Foo {
    fn modify(&mut self) {}
}

Bar 存储回调:

struct Bar<'a> {
    callback: Box<FnMut() + 'a>,
}
impl<'a> Bar<'a> {
    fn new<F: FnMut() + 'a>(f: F) -> Bar<'a> {
        Bar {
            callback: Box::new(f),
        }
    }
}

init() 取一片 Bar 并执行它们的回调:

init() takes a slice of Bar and executes their callbacks:

fn init(bars: &mut [Bar]) {
    for b in bars {
        (*b.callback)();
    }
}

现在是最有趣的:

在循环中更改 Foo 工作正常;在循环的每次迭代中 foo 被可变地借用并且 .modify() 被调用:

Changing Foo in a loop works fine; on each iteration of the loop foo is mutably borrowed and .modify() is called:

fn main() {
    let mut foo = Foo;

    for _ in 0..10 {
        foo.modify();
    }
}

在回调内部更改 Foo 不起作用:

Changing Foo inside of the callbacks does not work:

fn main() {
    let mut foo = Foo;

    let mut bar1 = Bar::new(|| foo.modify());
    let mut bar2 = Bar::new(|| foo.modify());

    init(&mut [bar1, bar2]);
}

在操场上试试,它有一个错误:

error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> src/main.rs:27:29
   |
26 |     let mut bar1 = Bar::new(|| foo.modify());
   |                             -- --- previous borrow occurs due to use of `foo` in closure
   |                             |
   |                             first mutable borrow occurs here
27 |     let mut bar2 = Bar::new(|| foo.modify());
   |                             ^^ --- borrow occurs due to use of `foo` in closure
   |                             |
   |                             second mutable borrow occurs here
...
30 | }
   | - first borrow ends here

如何为第 2 项实施类似的保证?

How to implement a similar guarantee for item 2?

推荐答案

您可以使用 RefCell:

You can use RefCell:

let foo = RefCell::new(Foo);

{
    let bar1 = Bar::new(|| foo.borrow_mut().modify());
    let bar2 = Bar::new(|| foo.borrow_mut().modify());
    init(&mut [bar1, bar2]);
}

let mut foo = foo.into_inner(); // extract foo to use in external API

小心borrow_mut(),如果值当前被借用,它会发生恐慌.

Be careful with borrow_mut(), it panics if the value is currently borrowed.

如果你可以改变Barinit(),你可以将值foo传递给init()> 与方法 modify() 分开:

If you can change Bar and init(), you can pass value foo to the init() separate from the method modify():

struct Bar<'a> {
    callback: Box<FnMut(&mut Foo) + 'a>,
}
impl<'a> Bar<'a> {
    fn new<F: FnMut(&mut Foo) + 'a>(f: F) -> Bar<'a> {
        Bar {
            callback: Box::new(f),
        }
    }
}

fn init(bars: &mut [Bar], arg: &mut Foo) {
    for b in bars {
        (*b.callback)(arg);
    }
}

let mut bar1 = Bar::new(|x| x.modify());
let mut bar2 = Bar::new(Foo::modify); // you can pass it without closure
init(&mut [bar1, bar2], &mut foo);

这篇关于如何将具有捕获的可变变量的回调视为正常的可变借用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆