今天我們將要介紹 Rust 最核心的關鍵:所有權系統, Rust 並沒有垃圾回收(Garbage Collection),通常情況下會導致記憶體洩露,但是 Rust 的所有權系統讓記憶體洩露的發生率降到極低。
Rust 的所有權有三個重點
有點抽象,很難理解?我們搭配所有權轉移的介紹,希望大家能夠更直接理解所有權的概念。
何時會發生所有權轉移?
賦值給另一個變數
fn main() {
    let s1 = String::from("Hello");
    let s2 = s1; // s1 的所有權轉移到 s2,s1 失去所有權
    // println!("{}", s1); // 拿到註解後,將發生編譯錯誤!因為 s1 已失去資料所有權
    println!("{}", s2); // 將顯示 Hello 
}
傳遞參數給函數
fn take_ownership(s: String) {
    println!("{}", s); // 顯示 Hello 
} // s 離開作用域後,資料將失效
fn main() {
    let s1 = String::from("Hello");
    take_ownership(s1); // s1 傳遞給函數參數,所有權已被轉移
    // println!("{}", s1); // s1 已失去資料所有權,去除註解後,將發生編譯錯誤
}
從函數回傳值
fn create_string() -> String {
    let s = String::from("Hello");
    s // 從函數返回值,所有權將轉移
}
fn main() {
    let s1 = create_string(); // 接收回傳的值,並取得所有權
    println!("{}", s1); // 顯示 Hello 
}
有些時候我們只是想要使用數值,但是不想轉移所有權時,就需要借用和引用。
不想轉移擁有權,只是想借用資料來讀取時,就需要採用不可變借用的方式。
範例:
fn calculate_length(s: &String) -> usize {
    s.len() // 可以讀取,但不能修改
}
fn main() {
    let s1 = String::from("Hello");
    let len = calculate_length(&s1); // 借用 s1, s1 不會失去所有權
    println!("'{}'的長度是 {}", s1, len); // 正常輸出 s1 的內容
}
我們想要修改借用的數值時,就需要加上 mut ,來完成可變借用。
範例:
fn change_string(s: &mut String) {
    s.push_str(", World!");
}
fn main() {
    let mut s = String::from("Hello");
    change_string(&mut s); // 可變借用
    println!("{}", s); // 輸出:Hello, World!
}
借用時需要特別注意,多個不可變借用可以同時存在,但是當宣告可變借用後,先前的不可變借用將失效。
fn main() {
    let mut s = String::from("Hello");
    // 多個不可變借用可以同時存在
    let s1 = &s;
    let s2 = &s;
    println!("{}", s1);
    println!("{}", s2);
    // 可變借用,先前的不可變借用將失效
    let s3 = &mut s;
    s3.push_str(" World");
    // println!("{}", s1); // 編譯錯誤,因為 s1 已經失效
    let s4 = &s;
    println!("{}", s4); // 正常,顯示 Hello World
}