Фон
Рассмотрим игрушечную задачу, в которой у меня есть структура 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
изменяется на каждой итерации l oop (так что он может убедитесь, что &mut x.next
заимствованные каждый раз были разными). Поэтому я провел эксперимент по изменению кода таким образом, чтобы компилятор не мог определить, так ли это, добавив условие if n % 2 == 0
к назначению tail = &mut x.next;
. Разумеется, это привело к ошибке компиляции, аналогичной предыдущей:
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