邁向 Rust

借用檢查器(borrow checker)

到目前為止的所有規則——唯一擁有者、指派即移動、多共享或一可變——如果沒有東西去檢查,就只是禮貌性的建議。借用檢查器就是 Rust 編譯器裡負責檢查的那一部分。它不是你另外執行的工具,也不是執行期的看門狗;它是編譯器內的一個階段,每次你建構時,它讀過你的程式碼,並證明每個參考都遵守所有權與借用規則。若它能證明你的程式安全,就編譯通過;若它找到哪怕一條規則可能被打破的途徑,就以一個借用檢查錯誤停下,程式無法建構。

它實際在做什麼,用白話分步說:對每個值,它算出該值的每份借用「存活(被使用)」涵蓋的程式碼範圍。然後它拿規則去對照這些範圍——沒有任何借用比它所指向的值活得久(所以沒有參考會懸置)、沒有任何可變借用與同一個值的其他借用重疊、以及你絕不在某個值被移走之後還使用它。借用檢查錯誤就是編譯器告訴你它無法證明上述某一條。訊息會點名你絆到的那條規則:無法借為可變因為它同時被借為不可變、使用已移動的值、或借用的值存活得不夠久。關鍵在於這些是編譯期錯誤——它們發生在你的機器上、在任何東西出貨之前,而不是在使用者面前當機。

誠實的部分:借用檢查器是保守的。它只接受能被它證明安全的程式碼,所以它有時會拒絕一個其實沒問題的程式,只因那份證明超出了它能看見的範圍。這就是新手所經歷、著名的「與借用檢查器搏鬥」。正確的反應通常不是硬把程式碼推過去,而是重新組織它讓所有權的故事更清楚——縮短一段借用、在真的需要兩份副本時 clone、或拆開一個函式。練習久了,檢查器就不再像個對手,而開始像個同事,替你抓出那些在 C 裡會無聲出貨、數週後才當機的、一模一樣的記憶體失誤。

fn main() { let r; { let x = 5; r = &x; // 借用 x } // x 在這裡被釋放 println!("{r}"); // error[E0597]:`x` 存活得不夠久 }

檢查器拒絕一個會比所指向的值活得更久的參考——在編譯期就被攔下。

借用檢查錯誤不是你程式裡等著在執行期發作的臭蟲——它是編譯器根本拒絕讓某類已知錯誤存在。它是保守的,所以被拒絕的程式有時其實安全;但對於被接受的程式,它的拒絕從不是假警報。

又称
borrowckthe checker借用檢查器