深入剖析:Rust 所有權系統

一、Rust 所有權系統是什麼

Rust 的所有權系統是該語言最爲獨特且核心的特性之一。它是一種用於管理內存的機制,在不需要垃圾回收(GC)機制的情況下,保障內存安全和運行效率。

在 Rust 中,每個值都有一個被稱爲其所有者(owner)的變量,並且這個值有且僅有一個所有者。例如,當創建一個變量來存儲某個值時,這個變量就成爲了該值的所有者。這一概念與其他編程語言中對內存管理的方式有很大的區別。像在 C 語言中,程序員需要手動管理內存的分配和釋放,容易出現內存泄漏(如分配了內存卻忘記釋放)和懸空指針(訪問已經釋放的內存)等問題;而在有垃圾回收機制的語言如 Java 中,垃圾回收器自動管理內存,但會有一定的性能開銷並且在某些情況下可能存在不可預測的暫停。

Rust 的所有權系統則基於一些簡單而嚴格的規則來運作。這些規則包括:每個值都有對應的所有者變量;在任何時刻,一個值只能有一個所有者;當所有者(變量)離開其作用域時,這個值將被自動丟棄(釋放其佔用的內存)。例如:

{
    let s = String::from("hello"); // s是"hello"這個字符串值的所有者
    // 在這個代碼塊內可以使用s
} // 代碼塊結束,s離開作用域,"hello"字符串所佔用的內存被釋放

二、Rust 所有權系統的特點

(一)基於變量的所有權歸屬

(二)所有權的轉移與生命週期管理

let s1 = String::from("rust"); 
let s2 = s1; 
// 此時s1不再擁有"rust"字符串的所有權,s2成爲新的所有者

這種所有權轉移機制在函數調用中也同樣適用。當把一個變量作爲參數傳遞給函數時,所有權會轉移到函數內部的參數變量。這一特性對於管理資源(如文件句柄、網絡連接等)非常有用。例如,當一個函數打開一個文件並返回文件句柄,在 Rust 中可以通過所有權轉移確保在函數外部不再對已經關閉的文件進行操作。

{
    let mut v = vec![1, 2, 3]; // v是向量[1, 2, 3]的所有者
    // 在這個代碼塊內可以對v進行操作
} // 代碼塊結束,v離開作用域,向量[1, 2, 3]所佔用的內存被釋放

這一特點避免了常見的內存泄漏問題,因爲程序員不需要手動去釋放內存,編譯器會根據所有權和作用域的規則自動處理。

(三)借用與引用的規則

let s = String::from("hello"); 
let s_ref = &s; 
// 這裏s仍然擁有"hello"字符串的所有權,s_ref是對s的不可變引用

在任何給定時間,可以有多個不可變引用存在。這對於在函數之間傳遞數據進行只讀操作非常方便,同時也保證了內存安全,因爲這些引用不能修改原始值,不會引起數據競爭。

let mut num = 5; 
let mut_ref = &mut num; 
// 此時只有mut_ref這一個可變引用可以修改num的值

這種限制確保了在修改數據時的獨佔性,避免了數據競爭和不一致性。如果違反了這個規則,編譯器會報錯。

三、Rust 所有權系統的工作原理

(一)基於堆棧的內存管理與所有權

(二)所有權規則的執行機制

{
    let s = String::from("rust"); 
    // s在這個代碼塊內是"rust"的所有者
} // 代碼塊結束,s離開作用域,"rust"字符串所佔用的內存被釋放

在函數調用中,參數的傳遞也涉及到所有權轉移和作用域的變化。當把一個變量作爲參數傳遞給函數時,這個變量在函數外部的作用域結束,而在函數內部,參數變量開始了新的作用域併成爲傳遞值的所有者(如果是值傳遞)。

(三)借用檢查機制

四、Rust 所有權系統的優勢

(一)內存安全保障

fn create_vector() -> Vec<i32> {
    let v = vec![1, 2, 3, 4, 5]; 
    // 當函數結束時,v離開作用域,向量v所佔用的內存被自動釋放
    v
}
int *func() {
    int a = 10; 
    return &a; 
}

在這個 C 函數中,返回了局部變量 a 的地址,當函數結束後,局部變量 a 的內存被釋放,但返回的指針仍然指向那塊已經釋放的內存,這就產生了懸空指針。而在 Rust 中,這種代碼是無法通過編譯的。

(二)高性能

(三)併發安全

五、Rust 所有權系統的應用場景

(一)系統編程

(二)網絡編程

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HFZj9pHMOO2DHjfL5WzsCw