- 每個值都有一個所有者(owner)
- 同一時間只能有一個所有者
- 當所有者離開作用域時,值會被丟棄(drop)
移動(Move)
當所有權從一個變量轉移到另一個變量時發生移動。
發生移動的情況:
// 1. 賦值時移動 let s1 = String::from("hello"); let s2 = s1; // s1 的所有權移動到 s2,s1 不再有效
// 2. 函數傳參時移動 fn take_ownership(s: String) { println!("{}", s); } let s = String::from("hello"); take_ownership(s); // s 的所有權移動到函數內,s 不再有效
// 3. 函數返回時移動 fn give_ownership() -> String { String::from("hello") // 所有權移動給調用者 }
注意: 實現了 Copy trait 的類型(如整數、浮點數、布爾值、字符)會複製而不是移動。
借用(Borrowing)
借用允許你引用某個值而不獲取其所有權。
不可變引用(Immutable Reference)&T
發生不可變借用的情況:
// 1. 創建不可變引用 let s1 = String::from("hello"); let len = calculate_length(&s1); // &s1 創建不可變引用
fn calculate_length(s: &String) -> usize { s.len() // 可以讀取,但不能修改 }
// 2. 多個不可變引用可以同時存在 let s = String::from("hello"); let r1 = &s; let r2 = &s; let r3 = &s; // 完全合法
規則:
- 可以同時存在多個不可變引用
- 不可變引用期間不能修改原值
- 引用必須始終有效(不能懸垂)
可變引用(Mutable Reference)&mut T
發生可變借用的情況:
// 1. 創建可變引用 let mut s = String::from("hello"); change(&mut s); // &mut s 創建可變引用
fn change(s: &mut String) { s.push_str(", world"); // 可以修改 }
// 2. 可變引用的限制 let mut s = String::from("hello"); let r1 = &mut s; // let r2 = &mut s; // 錯誤!同一時間只能有一個可變引用
規則:
- 同一時間只能有一個可變引用
- 可變引用存在時,不能有其他引用(可變或不可變)
- 防止數據競爭
各種情況總結
何時發生移動(Move)
- 非 Copy 類型的賦值:let b = a;
- 傳遞非 Copy 類型給函數:func(value)
- 從函數返回值:return value;
- 集合操作:vec.push(value)
何時使用不可變引用(&T)
- 只需要讀取數據
- 需要多個地方同時訪問
- 避免所有權轉移
- 函數參數不需要修改:fn read(s: &String)
何時使用可變引用(&mut T)
- 需要修改數據但不獲取所有權
- 函數需要修改參數:fn modify(s: &mut String)
- 原地修改而不是返回新值
引用的生命週期規則
// 正確:引用的生命週期不超過所有者 { let s = String::from("hello"); let r = &s; // r 的生命週期在 s 之內 println!("{}", r); } // s 和 r 都離開作用域
// 錯誤:懸垂引用 // fn dangle() -> &String { // let s = String::from("hello"); // &s // 錯誤!s 將被銷燬,返回的引用無效 // }
借用檢查器的關鍵點
不可變引用和可變引用不能共存:
let mut s = String::from("hello");
let r1 = &s; // 不可變引用 let r2 = &s; // 不可變引用 println!("{} {}", r1, r2); // r1 和 r2 在此之後不再使用
let r3 = &mut s; // 可變引用 - 合法,因為 r1 和 r2 已經不再使用 println!("{}", r3);
引用的作用域從聲明開始,到最後一次使用結束(非詞法作用域,NLL - Non-Lexical Lifetimes)。
實用建議
- 優先使用引用而不是移動所有權
- 默認使用不可變引用,只在必要時使用可變引用
- 利用作用域來管理引用的生命週期
- 理解 Copy vs Clone:Copy 是隱式的棧複製,Clone 是顯式的深拷貝
這套系統在編譯時保證了內存安全,避免了數據競爭、懸垂指針和雙重釋放等問題。