为什么匹配的可变引用的条件赋值会导致借用错误?
Why does conditional assignment of a matched mutable reference cause borrow errors?
我无法理解为什么这会导致错误:
#[derive(Debug)]
pub struct Node {
next: Option<Box<Node>>,
}
pub fn print_root_or_next(root: &mut Node, try_next: bool) {
let mut current = root;
match &mut current.next {
Some(node) => {
if try_next {
current = &mut *node;
}
}
None => return,
}
println!("{:?}", current);
}
error[E0502]: cannot borrow `current` as immutable because it is also borrowed as mutable
--> src/lib.rs:17:22
|
8 | match &mut current.next {
| ----------------- mutable borrow occurs here
...
17 | println!("{:?}", current);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
我看不出有冲突的借用;甚至错误消息似乎也表明两次借用是一回事。这是借用检查器的问题还是这个例子在某些方面确实存在缺陷?
我对这个限制很感兴趣。我对实现不太了解,但考虑到基本的 if
:
if try_next {
current = &mut *current.next.as_mut().unwrap();
}
和基本 match
:
match &mut current.next {
Some(node) => {
current = &mut *node;
}
None => return,
}
甚至反转它们:
if try_next {
match &mut current.next {
Some(node) => {
current = &mut *node;
}
None => return,
}
}
一切正常,一定有一些事情是借阅检查员正在考虑或没有考虑的,这与我对原始表格为何不起作用的理解相冲突。
我认为问题在于 current
本身就是有条件的再借。
考虑删除条件但使用两个变量的更简单的代码:
#[derive(Debug)]
pub struct Node {
next: Option<Box<Node>>,
}
pub fn print_root_or_next(root: &mut Node) {
let a = root;
let b;
match &mut a.next {
Some(node) => {
b = &mut *node;
}
None => return,
}
println!("{:?}", a);
println!("{:?}", b);
}
这失败了,正如您所期望的错误消息:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/lib.rs:16:22
|
9 | match &mut a.next {
| ----------- mutable borrow occurs here
...
16 | println!("{:?}", a);
| ^ immutable borrow occurs here
17 | println!("{:?}", b);
| - mutable borrow later used here
也就是说,a
是可变借用的,并且由于 b
而使借用保持有效。所以当 b
还活着时你不能使用 a
。
如果你重新排序最后两行 println!
,它编译没有问题,因为词法生命周期:b
被打印然后被遗忘,释放借用并使 a
再次可用。
现在,看看另一个变体,与您的变体相似,但没有 if
:
pub fn print_root_or_next(root: &mut Node) {
let mut c = root;
match &mut c.next {
Some(node) => {
c = &mut *node;
}
None => return,
}
println!("{:?}", c);
}
它编译也很好,因为当 c
被重新借用时,它被重新分配。从这一点开始,它就像前面示例中的 b
一样工作。你可以自由使用b
,禁止使用a
,这里不再提供。
返回您的代码:
pub fn print_root_or_next(root: &mut Node, test: bool) {
let mut c = root;
match &mut c.next {
Some(node) => {
if test {
c = &mut *node;
}
}
None => return,
}
println!("{:?}", c);
}
这里的问题是,当c
被重新借用时,它是有条件地完成的,编译器不知道它会是哪一个,像a
或像b
来自上面的例子。所以它必须假设它是同时存在的!但是从示例中我们看到,当 b
处于活动状态时,您不能使用 a
,但由于它们都是相同的值,因此不能再使用该值。
当编译器抱怨这个奇怪的错误消息时:
17 | , current);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
实际意思是:
17 | , current);
| ^^^^^^^
| |
| immutable borrow occurs here if try_next is false
| mutable borrow at the same time used here if try_next is true
我不知道这是否是编译器的限制,使用这个有条件地重新借用自身的引用实际上是安全的。也许这是对借用检查的限制,或者也许有一些我不明白的微妙之处......我怀疑如果你包括多个条件或多个参考,允许这可能是不合理的。
我无法理解为什么这会导致错误:
#[derive(Debug)]
pub struct Node {
next: Option<Box<Node>>,
}
pub fn print_root_or_next(root: &mut Node, try_next: bool) {
let mut current = root;
match &mut current.next {
Some(node) => {
if try_next {
current = &mut *node;
}
}
None => return,
}
println!("{:?}", current);
}
error[E0502]: cannot borrow `current` as immutable because it is also borrowed as mutable
--> src/lib.rs:17:22
|
8 | match &mut current.next {
| ----------------- mutable borrow occurs here
...
17 | println!("{:?}", current);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
我看不出有冲突的借用;甚至错误消息似乎也表明两次借用是一回事。这是借用检查器的问题还是这个例子在某些方面确实存在缺陷?
我对这个限制很感兴趣。我对实现不太了解,但考虑到基本的 if
:
if try_next {
current = &mut *current.next.as_mut().unwrap();
}
和基本 match
:
match &mut current.next {
Some(node) => {
current = &mut *node;
}
None => return,
}
甚至反转它们:
if try_next {
match &mut current.next {
Some(node) => {
current = &mut *node;
}
None => return,
}
}
一切正常,一定有一些事情是借阅检查员正在考虑或没有考虑的,这与我对原始表格为何不起作用的理解相冲突。
我认为问题在于 current
本身就是有条件的再借。
考虑删除条件但使用两个变量的更简单的代码:
#[derive(Debug)]
pub struct Node {
next: Option<Box<Node>>,
}
pub fn print_root_or_next(root: &mut Node) {
let a = root;
let b;
match &mut a.next {
Some(node) => {
b = &mut *node;
}
None => return,
}
println!("{:?}", a);
println!("{:?}", b);
}
这失败了,正如您所期望的错误消息:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/lib.rs:16:22
|
9 | match &mut a.next {
| ----------- mutable borrow occurs here
...
16 | println!("{:?}", a);
| ^ immutable borrow occurs here
17 | println!("{:?}", b);
| - mutable borrow later used here
也就是说,a
是可变借用的,并且由于 b
而使借用保持有效。所以当 b
还活着时你不能使用 a
。
如果你重新排序最后两行 println!
,它编译没有问题,因为词法生命周期:b
被打印然后被遗忘,释放借用并使 a
再次可用。
现在,看看另一个变体,与您的变体相似,但没有 if
:
pub fn print_root_or_next(root: &mut Node) {
let mut c = root;
match &mut c.next {
Some(node) => {
c = &mut *node;
}
None => return,
}
println!("{:?}", c);
}
它编译也很好,因为当 c
被重新借用时,它被重新分配。从这一点开始,它就像前面示例中的 b
一样工作。你可以自由使用b
,禁止使用a
,这里不再提供。
返回您的代码:
pub fn print_root_or_next(root: &mut Node, test: bool) {
let mut c = root;
match &mut c.next {
Some(node) => {
if test {
c = &mut *node;
}
}
None => return,
}
println!("{:?}", c);
}
这里的问题是,当c
被重新借用时,它是有条件地完成的,编译器不知道它会是哪一个,像a
或像b
来自上面的例子。所以它必须假设它是同时存在的!但是从示例中我们看到,当 b
处于活动状态时,您不能使用 a
,但由于它们都是相同的值,因此不能再使用该值。
当编译器抱怨这个奇怪的错误消息时:
17 | , current);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
实际意思是:
17 | , current);
| ^^^^^^^
| |
| immutable borrow occurs here if try_next is false
| mutable borrow at the same time used here if try_next is true
我不知道这是否是编译器的限制,使用这个有条件地重新借用自身的引用实际上是安全的。也许这是对借用检查的限制,或者也许有一些我不明白的微妙之处......我怀疑如果你包括多个条件或多个参考,允许这可能是不合理的。