执行回调,就像循环中的可变借用一样 [英] Execute callbacks like as mutable borrowing from cycle
问题描述
可以使用方法
.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)();
}
}
现在最有趣的是:
-
在周期中更改
Foo
:
pre>fn main(){
let mut foo = Foo;
for _ in 0..10 {
foo.modify();
}
}
在循环的每次迭代
li>foo
是可变借用的,并且调用.modify()
。
-
在回调中更改
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:
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.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屋!