[英]In Rust, what's the difference between "shadowing" and "mutability"?
在Rust Book 的第 3 章,變量和可變性中,我們對這個主題進行了幾次迭代,以演示 Rust 中變量的默認、不可變行為:
fn main() {
let x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
哪些輸出:
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
3 | println!("The value of x is {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
然而,由於 Rust 對陰影變量的看法,我們可以簡單地這樣做來改變仍然“不可變”的x
:
fn main() {
let x = 5;
println!("The value of x is {}", x);
let x = 6;
println!("The value of x is {}", x);
}
哪些輸出(跳過細節):
The value of x is 5
The value of x is 6
有趣的是,這段代碼也產生了上面的兩行作為輸出,盡管我們沒有調用let
而是在第一次x
綁定到5
時調用了mut
:
fn main() {
let mut x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
這種在如何(並非真的)保護變量免於重新分配方面的模糊性似乎與保護綁定到不可變(Rust 默認)變量的值的既定目標背道而馳。 來自同一章(其中還包含陰影部分):
當我們嘗試更改我們之前指定為不可變的值時,我們會遇到編譯時錯誤,這一點很重要,因為這種情況會導致錯誤。 如果我們的代碼的一部分基於值永遠不會改變的假設而運行,而我們代碼的另一部分更改了該值,則代碼的第一部分可能不會執行其設計的目的。 這種錯誤的原因事后很難追查,尤其是當第二段代碼只是偶爾更改值時。
在 Rust 中,編譯器保證當你聲明一個值不會改變時,它真的不會改變。 這意味着當您閱讀和編寫代碼時,您不必跟蹤值可能發生變化的方式和位置。 因此,您的代碼更容易推理。
如果我可以通過一個足夠無辜的調用let
我的不可變x
這個重要特性被mut
,為什么我需要mut
? 有什么方法可以真正地,認真地讓x
不可變,這樣就沒有let x
可以重新分配其值?
我相信混淆是因為您將名稱與存儲混為一談。
fn main() {
let x = 5; // x_0
println!("The value of x is {}", x);
let x = 6; // x_1
println!("The value of x is {}", x);
}
在此示例中,有一個名稱 ( x
) 和兩個存儲位置( x_0
和x_1
)。 第二個let
只是重新綁定名稱x
以引用存儲位置x_1
。 x_0
存儲位置完全不受影響。
fn main() {
let mut x = 5; // x_0
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
在此示例中,有一個名稱 ( x
) 和一個存儲位置 ( x_0
)。 x = 6
賦值直接改變了存儲位置x_0
的位。
你可能會爭辯說這些做同樣的事情。 如果是這樣,你就錯了:
fn main() {
let x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
let x = 6; // x_1
println!("The value of y is {}", y);
}
這輸出:
The value of y is 5
The value of y is 5
這是因為更改x
所指的存儲位置對存儲位置x_0
絕對沒有影響,即y_0
包含指向的指針。 然而,
fn main() {
let mut x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
x = 6;
println!("The value of y is {}", y);
}
這將無法編譯,因為您無法在借用x_0
時對其進行變異。
Rust 關心防止通過引用觀察到的不需要的突變效應。 這與允許遮蔽並不沖突,因為您在遮蔽時不會更改值,您只是在以其他任何地方都無法觀察到的方式更改特定名稱的含義。 陰影是嚴格的局部變化。
所以是的,你絕對可以保持x
的值不被改變。 您不能做的是保持名稱x
所指的內容不被更改。 最多,您可以使用像clippy
類的clippy
來拒絕將陰影視為 lint。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.