【发布时间】:2020-07-13 04:55:04
【问题描述】:
背景
考虑一个玩具问题,其中我有一个 Node 结构,它表示链表的节点,我想创建一个函数来构建一个值从 1 到 9 的列表。以下代码按预期工作:
struct Node {
val: i32,
next: Option<Box<Node>>,
}
fn build_list() -> Option<Box<Node>> {
let mut head = None;
let mut tail = &mut head;
for n in 1..10 {
*tail = Some(Box::new(Node {val: n, next: None}));
if let Some(ref mut x) = tail {
tail = &mut x.next;
};
}
head
}
但是如果我将build_list函数中的匹配表达式修改为如下,编译失败:
fn build_list() -> Option<Box<Node>> {
let mut head = None;
let mut tail = &mut head;
for n in 1..10 {
*tail = Some(Box::new(Node {val: n, next: None}));
if let Some(x) = tail.as_mut() {
tail = &mut x.next;
};
}
head
}
编译错误:
error[E0506]: cannot assign to `*tail` because it is borrowed
--> src/main.rs:72:9
|
72 | *tail = Some(Box::new(Node {val: n, next: None}));
| ^^^^^
| |
| assignment to borrowed `*tail` occurs here
| borrow later used here
73 | {
74 | if let Some(x) = tail.as_mut() {
| ---- borrow of `*tail` occurs here
error[E0499]: cannot borrow `*tail` as mutable more than once at a time
--> src/main.rs:74:30
|
74 | if let Some(x) = tail.as_mut() {
| ^^^^ mutable borrow starts here in previous iteration of loop
问题
在这个例子中,有什么区别
if let Some(ref mut x) = tail
和
if let Some(x) = tail.as_mut()
?
(作为一个学习 Rust 的初学者)我希望这些匹配表达式是等价的,但显然我缺少一些细微的差异。
更新
我清理了原始示例中的代码,这样我就不需要列表头部的占位符元素了。差异(和编译错误)仍然存在,我只是得到一个额外的编译错误分配给借来的*tail。
更新 2
(这只是一个奇怪的观察,无助于回答原始问题)
在考虑了@Emoun 的回答之后,编译器应该能够知道tail 在循环的每次迭代中都在变化(这样它可以确保每次都借用&mut x.next)这听起来很重要(在第一个工作示例中)不同)。所以我做了一个实验,通过在tail = &mut x.next; 赋值中添加if n % 2 == 0 条件,以编译器无法判断是否是这种情况的方式更改代码。果然,导致了和另外一个类似的编译错误:
fn build_list() -> Option<Box<Node>> {
let mut head = None;
let mut tail = &mut head;
for n in 1..10 {
*tail = Some(Box::new(Node {val: n, next: None}));
if let Some(ref mut x) = tail {
if n % 2 == 0 {
tail = &mut x.next;
}
};
}
head
}
新的错误:
error[E0506]: cannot assign to `*tail` because it is borrowed
--> src/main.rs:60:9
|
60 | *tail = Some(Box::new(Node {val: n, next: None}));
| ^^^^^
| |
| assignment to borrowed `*tail` occurs here
| borrow later used here
61 | if let Some(ref mut x) = tail {
| --------- borrow of `*tail` occurs here
error[E0503]: cannot use `*tail` because it was mutably borrowed
--> src/main.rs:61:16
|
61 | if let Some(ref mut x) = tail {
| ^^^^^---------^
| | |
| | borrow of `tail.0` occurs here
| use of borrowed `tail.0`
| borrow later used here
error[E0499]: cannot borrow `tail.0` as mutable more than once at a time
--> src/main.rs:61:21
|
61 | if let Some(ref mut x) = tail {
| ^^^^^^^^^ mutable borrow starts here in previous iteration of loop
【问题讨论】:
-
if let Some(x) = tail似乎也有效。不幸的是,我对任何一种情况都没有解释。 -
tail.as_mut()的返回值的生命周期似乎与tail相同,因此只是编译器限制。在循环内移动let tail = &mut head使其工作。 -
This 看起来非常相似。
-
谁想知道为什么
Some(x)可以匹配&mut Option<Box<Node>>的类型应该寻找rust match ergonomics。 -
@CoronA ,
if let Some(x) = tail确实有效,这也让我感到惊讶(学到了新东西,谢谢!)。