gpt4 book ai didi

rust - 使用引用枢轴循环时发生可变借用问题

转载 作者:行者123 更新时间:2023-12-05 01:27:12 26 4
gpt4 key购买 nike

struct A {
next: Option<Box<A>>,
}

impl A {
fn grow(&mut self) {
self.next = Some(Box::new(A { next: None }));
}
}

fn main() {
let mut a = A{ next: Some(Box::new(A { next: None }))};
let mut p = &mut a;
// attempt to append to the list
loop {
match &mut p.next {
Some(n) => p = n,
None => {
p.grow();
break;
}
}
}
}

上面的代码是来自更复杂数据结构的简化逻辑,能够重现借用检查器投诉:

error[E0499]: cannot borrow `*p` as mutable more than once at a time
--> t.rs:19:17
|
16 | match &mut p.next {
| ----------- first mutable borrow occurs here
...
19 | p.grow();
| ^
| |
| second mutable borrow occurs here
| first borrow later used here

error: aborting due to previous error

为什么 p 在 match case 中仍然被认为是可变借用的?而且,尝试将 p.update() 移出循环也无济于事:

fn main() {
let mut a = A{ next: Some(Box::new(A { next: None }))};
let mut p = &mut a;
// attempt to append to the list
loop {
match &mut p.next {
Some(n) => p = n,
None => {
break;
}
}
}
p.grow();
}

我在这种情况下遇到了同样的错误。我知道 p = n 是导致问题的原因,因为它在没有它的情况下编译通过,但为什么呢?

最佳答案

这是我对正在发生的事情的看法。为了解释它,我在不改变想法的情况下稍微简化了你的代码:

fn main() {
let mut a = A{ next: Some(Box::new(A { next: None }))};
let mut p = &mut a;
let next = &mut p.next;
if let Some(n) = next {
p = n;
}

p.grow();
}

此代码会产生与您的代码相同的错误。更有趣的是,您不能以任何方式在 main 的末尾使用 p。甚至 println!("{:?}", p) 也会产生相同的错误。

编译器检查代码可以执行的所有方式,并发现在调用 p.grow() 时,p 可以指向 a,或 a.next.as_mut()(我的意思是 a.next 选项结构的内部值)。但是 p.grow() 需要使用其中一个引用。

如果p == &mut a,我们调用p.grow(),那么引用a.next.as_mut() 变得无效,因此出错。如果 p == a.next.as_mut(),我们调用 p.grow(),我们引用 &mut a 两次,如第一次借用不能被放弃。

如果不赋值p = n,就没有这个问题,因为只有一个有效的引用,编译器可以在p.grow() 被调用。

在这个例子中实际上有3种方法来防止编译错误:

  1. 移除p = n赋值。
  2. p.grow() 移到 if let block 中,从而确保在调用时 p 引用内部值.
  3. 如果 next 是 Some,则退出 main:
if let Some(n) = next {
p = n;
} else {
return;
}

p.grow();

后者之所以有效,是因为编译器肯定知道在 p.grow() 调用时不需要先借用并且可以删除,而 p 可以指向仅限于内在值(value)。

原题中的问题是一样的。编译器必须确定在 p.grow() 调用时 p 引用了什么。

在解决方案中,由 Lagerbaer 提供, p在调用p.grow()时只能引用某个值(此时没有引用p.next) ,因此它有效:

    let mut p = &mut a;
// attempt to append to the list
loop {
match p.next {
Some(ref mut n) => p = n,
None => {
p.grow();
break;
}
}
}

关于rust - 使用引用枢轴循环时发生可变借用问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69591784/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com