簡體   English   中英

為什么變量的可變性沒有反映在 Rust 的類型簽名中?

[英]Why is the mutability of a variable not reflected in its type signature in Rust?

據我了解,可變性並未反映在變量類型簽名中。 例如,這兩個引用具有相同的類型簽名&i32

let ref_foo : &i32 = &foo;
let mut ref_bar : &i32 = &bar;

為什么會這樣? 這似乎是一個非常重大的疏忽。 我的意思是,即使是 C/C++ 也更明確地使用兩個const來表示我們有一個指向const數據的const指針:

const int * const ptr_foo = &foo;
const int * ptr_bar = &bar;

有沒有更好的方法來思考這個問題?

可變性是 Rust 中綁定的一個屬性,而不是類型的屬性。

一個值的唯一所有者總是可以通過將它移動到一個可變綁定來改變它:

let s = "Hi".to_owned();  // Create an owned value.
s.push('!');              // Error because s is immutable.
let mut t = s;            // Move owned value to mutable binding.
t.push('!');              // Now we can modify the string.

這表明可變性不是值類型的屬性,而是其綁定的屬性。 該代碼當然僅在當前未借用該值時才有效,這會阻止移動該值。 共享借用仍然保證是不可變的。

引用的可變性與綁定的可變性正交。 Rust 使用相同的mut關鍵字來消除兩種類型的引用的歧義,但它是一個單獨的概念。

內部可變性模式再次與上述正交,因為它類型的一部分。 即使只持有對它們的共享引用,也可以修改包含CellRefCell或類似內容的類型。

完成改變值后,將值重新綁定為不可變是一種常見模式:

let mut x = ...;
// modify x ...
let x = x;

Rust 中的所有權語義和類型系統與 C++ 有點不同,我更喜歡 Rust 的方式。 我不認為它天生就缺乏表現力,正如你所暗示的那樣。

C++ 和 Rust 中的常量根本不同。 在 C++ 中,常量是任何類型的屬性,而在 Rust 中,它是引用的屬性。 因此,在 Rust 中沒有真正的常量類型。

以這個 C++ 代碼為例:

void test() {
    const std::string x;
    const std::string *p = &x;
    const std::string &r = x;
}

變量x被聲明為常量類型,因此對它創建的任何引用也將是常量,並且任何修改它的嘗試(例如使用const_cast )都將呈現未定義的行為 請注意const如何成為對象類型的一部分。

然而,在 Rust 中,沒有辦法聲明一個常量變量:

fn test() {
    let x = String::new();
    let r = &x;

    let mut x = x; //moved, not copied, now it is mutable!
    let r = &mut x;
}

在這里, const-ness 或 mut-ness 不是變量類型的一部分,而是每個引用的屬性。 甚至變量的原始名稱也可以視為引用。

因為當你在 C++ 或 Rust 中聲明一個局部變量時,你實際上是在做兩件事:

  • 創建對象本身。
  • 聲明一個名稱來訪問對象,各種引用

當您編寫 C++ 常量時,您同時創建了常量、對象和引用。 但是在 Rust 中沒有常量對象,所以只有引用是常量。 如果您移動對象,您會處理原始名稱並綁定到一個新名稱,這可能是可變的,也可能不是。

請注意,在 C++ 中,您不能移動常量對象,它將永遠保持不變。

關於有兩個consts作為指針,它們在 Rust 中是一樣的,如果你有兩個間接引用:

fn test() {
    let mut x = String::new();
    let p: &mut String = &mut x;
    let p2: &&mut String = &p;
}

關於什么更好,這是一個品味問題,但請記住常量在 C++ 中可以做的所有奇怪的事情:

  • 常量對象總是常量,除非它不是:構造函數和析構函數。
  • 具有可變成員的常量類並不是真正的常量。 mutable不是類型系統的一部分,而 Rust 的Cell/RefCell是。
  • 具有常量成員的類使用起來很痛苦:默認構造函數和復制/移動運算符不起作用。

在 C++ 中,默認情況下一切都是可變的, const關鍵字表示您想要更改該行為。

在銹一切都是默認的IM可變的,而mut關鍵字表示要改變這種行為。

請注意,對於指針,Rust 確實需要mutconst關鍵字:

let ref_foo : *const i32 = &foo;
let mut ref_bar : *const i32 = &bar;

因此,您的示例是等效的,但 Rust 不那么冗長,因為它默認為不可變的。

甚至 C/C++ 在這方面做得更好

多年的 C++ 和 Rust 開發經驗使我確信 Rust 處理可變性的方式(例如,默認為不可變,但還有其他差異)要好得多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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