执行回调,就像循环中的可变借用一样 [英] Execute callbacks like as mutable borrowing from cycle

查看:82
本文介绍了执行回调,就像循环中的可变借用一样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以使用方法 .modify()


$来修改Foo
  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 他们的回调:

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

现在最有趣的是:


  1. 在周期中更改 Foo



    pre> fn main(){
    let mut foo = Foo;

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

    在循环的每次迭代 foo 是可变借用的,并且调用 .modify()

    li>
  2. 在回调中更改 Foo

     code> fn main(){
    let mut foo = Foo;

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

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





$ b b

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

 错误:一次不能借用`foo`一次多次变量[E0499 ] 
let mut bar2 = Bar :: new(|| foo.modify());
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $ b let mut bar2 = Bar :: new(|| foo.modify());
^ ~~
注意:以前的借用`foo`在这里发生由于在闭包中使用;可变借用防止随后的移动,借用或修改`foo`,直到借用结束
let mut bar1 = Bar :: new(|| foo.modify());
^ ~~~~~~~~~~~~~~~~
注意:以前的借用在这里结束
fn main(){
...
}
^

如何对项目2实施类似的保证?

解决方案

您可以使用 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(); //提取foo用于外部API

小心 borrow_mut(),如果该值目前已借用,则会发生混乱。






如果您可以更改 Bar init(),可以将值 foo 传递给与方法 modify()分开的 init()

  ... 
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)
}
}
...
let mut bar1 = Bar :: new(| x | x.modify());
let mut bar2 = Bar :: new(Foo :: modify); //你可以传递它没有关闭
init(& mut [bar1,bar2],& mut foo);


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

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

Bar stores a callback:

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() takes a slice of Bar and executes their callbacks:

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

And now the most interesting:

  1. Change Foo in the cycle:

    fn main() {
        let mut foo = Foo;
    
        for _ in 0..10 {
            foo.modify();
        }
    }
    

    This works fine; on each iteration of the loop foo is mutably borrowed and .modify() is called.

  2. Change Foo in the callbacks:

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

Try it on the playground, it has an error:

error: cannot borrow `foo` as mutable more than once at a time [E0499]
    let mut bar2 = Bar::new(|| foo.modify());
                            ^~~~~~~~~~~~~~~
help: see the detailed explanation for E0499
note: borrow occurs due to use of `foo` in closure
    let mut bar2 = Bar::new(|| foo.modify());
                               ^~~
note: previous borrow of `foo` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends
    let mut bar1 = Bar::new(|| foo.modify());
                            ^~~~~~~~~~~~~~~
note: previous borrow ends here
fn main() {
...
}
^

How to implement a similar guarantee for item 2?

解决方案

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

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


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天全站免登陆