![](/img/trans.png)
[英]What is the difference between `Some(&a) => a` and `Some(a) => *a` when matching an Option?
[英]What is the difference between matching a mutable Option reference in “if let Some(ref mut x) = option” and in “if let Some(x) = option.as_mut()”?
考慮一個玩具問題,其中我有一個表示鏈表節點的Node
結構,並且我想創建一個 function 來構建一個值從 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
function 中的匹配表達式修改為以下內容,則無法編譯:
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
。
(這只是一個奇怪的觀察,無助於回答原始問題)在考慮了@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
你的代碼的第二個版本失敗的原因是因為 rust 的方法/函數總是借用整個對象,而不是它們的一部分。
在您的情況下,這意味着tail.as_mut()
可變地借用tail
,只要使用tail
,這種借用就會保持有效:
...
for n in 1..10 {
*tail = Some(Box::new(Node {val: n, next: None})); // Error in the second iteration,
// 'tail' was already borrowed
if let Some(x) = tail.as_mut() { // <-+ Borrow of 'tail' starts in the first iteration
tail = &mut x.next; // <-+ 'tail' now borrows itself
}; // |
} // <-+ Borrow of 'tail' ends here, after the last iteration
...
由於x
是tail
的借用, &mut x.next
也是tail
的借用,這意味着tail = &mut x.next
是tail
借用本身。 因此, tail
的初始借用不能 go 超出 scope,只要tail
在 scope 中。 每次迭代都使用tail
,因此在循環的最后一次迭代之后,借位只能從scope中借出go。
現在,為什么第一個版本的build_list
可以工作? 簡而言之:因為tail
永遠不會被借來。 if let Some(ref mut x) = tail
是將tail
解構為其組件(在本例中為Option::Some
和x
)。 這不是作為一個整體借用tail
,它只是借用x
。 然后當您使用tail = &mut x.next
時,您現在還將x
解構為其組件(僅提取next
),並使用tail
借用它。 在下一次迭代中, tail
不會被借用,因此可以很高興地重新分配。
方法/函數調用受到限制,因為它們不知道您稍后將使用 object 的哪些部分。 因此, as_mut()
必須借用整個tail
,即使您只使用它的一部分。 這是類型系統的限制,也是 getter/setter 方法比直接調用結構的成員更弱/更受限制的原因之一:getter/setter 將強制您借用整個結構,而直接訪問成員只會借用它成員而不是其他人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.