迭代递归结构时无法获得可变引用:一次不能多次借用可变变量 [英] Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
问题描述
我试图迭代导航递归数据结构,以便在某个位置插入元素.据我有限的理解,这意味着要可变引用结构的根,并依次用对它的跟随者的引用来替换它:
type Link = Option<Box<Node>>;
struct Node {
next: Link
}
struct Recursive {
root: Link
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(ref mut node) = *anchor {
anchor = &mut node.next;
}
anchor
}
}
(铁锈操场链接) >
但是,这失败了:
error[E0499]: cannot borrow `anchor.0` as mutable more than once at a time
--> src/main.rs:14:24
|
14 | while let Some(ref mut node) = *anchor {
| ^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
18 | }
| - first borrow ends here
error[E0506]: cannot assign to `anchor` because it is borrowed
--> src/main.rs:15:13
|
14 | while let Some(ref mut node) = *anchor {
| ------------ borrow of `anchor` occurs here
15 | anchor = &mut node.next;
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `anchor` occurs here
error[E0499]: cannot borrow `*anchor` as mutable more than once at a time
--> src/main.rs:17:9
|
14 | while let Some(ref mut node) = *anchor {
| ------------ first mutable borrow occurs here
...
17 | anchor
| ^^^^^^ second mutable borrow occurs here
18 | }
| - first borrow ends here
这很有意义,因为anchor
和node
都引用相同的结构,但是实际上我在分解后不再关心anchor
.
如何使用安全的Rust正确实现back()
?
可能...但是我希望我有一个更优雅的解决方案.
诀窍是不要向anchor
借钱,因此要在两个累加器之间玩弄:
- 持有对当前节点的引用
- 另一个被分配了对下一个节点的引用
这导致我:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
let tmp = anchor;
if let Some(ref mut node) = *tmp {
anchor = &mut node.next;
} else {
anchor = tmp;
break;
}
}
anchor
}
}
不太漂亮,但这是借项检查器可以做到的,所以\ _(ツ)_/¯.
@ker通过创建一个未命名的临时文件对此进行了改进:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
match {anchor} {
&mut Some(ref mut node) => anchor = &mut node.next,
other => return other,
}
}
}
}
这里的窍门是使用{anchor}
moves 将anchor
的内容移动到一个未命名的临时文件中,在该临时文件上执行匹配.因此,在match
块中,我们不是从anchor
借用,而是从临时借用的,这使我们可以自由修改anchor
.参见相关博客文章填充身份函数可以(在Rust中).
I'm trying to navigate a recursive data structure iteratively in order to insert elements at a certain position. To my limited understanding, this means taking a mutable reference to the root of the structure and successively replacing it by a reference to its follower:
type Link = Option<Box<Node>>;
struct Node {
next: Link
}
struct Recursive {
root: Link
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(ref mut node) = *anchor {
anchor = &mut node.next;
}
anchor
}
}
However, this fails:
error[E0499]: cannot borrow `anchor.0` as mutable more than once at a time
--> src/main.rs:14:24
|
14 | while let Some(ref mut node) = *anchor {
| ^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
18 | }
| - first borrow ends here
error[E0506]: cannot assign to `anchor` because it is borrowed
--> src/main.rs:15:13
|
14 | while let Some(ref mut node) = *anchor {
| ------------ borrow of `anchor` occurs here
15 | anchor = &mut node.next;
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `anchor` occurs here
error[E0499]: cannot borrow `*anchor` as mutable more than once at a time
--> src/main.rs:17:9
|
14 | while let Some(ref mut node) = *anchor {
| ------------ first mutable borrow occurs here
...
17 | anchor
| ^^^^^^ second mutable borrow occurs here
18 | }
| - first borrow ends here
This makes sense as both anchor
and node
refer to the same structure, but I actually don't care about anchor
any more after destructuring it.
How could back()
be implemented correctly using safe Rust?
It is possible... but I wish I had a more elegant solution.
The trick is NOT to borrow from anchor
, and therefore to juggle between two accumulators:
- one holding the reference to the current node
- the other being assigned the reference to the next node
This leads me to:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
let tmp = anchor;
if let Some(ref mut node) = *tmp {
anchor = &mut node.next;
} else {
anchor = tmp;
break;
}
}
anchor
}
}
Not exactly pretty, but this is something the borrow checker can get behind so ¯\_(ツ)_/¯.
@ker has improved on this by creating an unnamed temporary:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
match {anchor} {
&mut Some(ref mut node) => anchor = &mut node.next,
other => return other,
}
}
}
}
The trick here is that using {anchor}
moves the content of anchor
into an unnamed temporary on which the match executes. Therefore, in the match
block we are not borrowing from anchor
but from the temporary, leaving us free to modify anchor
. See the related blog post Stuff the Identity Function Does (in Rust).
这篇关于迭代递归结构时无法获得可变引用:一次不能多次借用可变变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!