簡體   English   中英

在 Rust 中,“陰影”和“可變性”有什么區別?

[英]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_0x_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM