文章目錄
- 第四章:Ownership 所有權
- 核心概念
- 關鍵機制
- 引用與借用(Reference & Borrowing)
- 懸垂引用問題
- 錯誤示例分析
- 解決方案
- 引用安全規則
- 切片(Slice)
- 內存安全保證
第四章:Ownership 所有權
Ownership is Rust’s most unique feature, and it enables Rust to make memory safety guarantees without needing a garbage collector.
核心概念
所有權三原則:
- 每個值有且只有一個所有者
- 所有權可轉移(move)
- 所有者離開作用域時值自動釋放(drop)
- Each value in Rust has a variable that’s called its owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
內存管理:
- 棧(Stack):固定大小數據,高效自動管理
- 堆(Heap):動態大小數據,需顯式分配
Example:
fn main() {let mut s = String::from("hello");s.push_str(", world!"); // push_str() appends a literal to a Stringprintln!("{}", s); // This will print `hello, world!`
}
Note: In C++, this pattern of deallocating resources at the end of an item’s lifetime is sometimes called Resource Acquisition Is Initialization (RAII). The drop function in Rust will be familiar to you if you’ve used RAII patterns.
關鍵機制
-
移動語義(Move):
- 賦值操作默認轉移所有權(非淺拷貝)
- 原變量隨即失效,防止懸垂指針
let s1 = String::from("hello"); let s2 = s1; // s1所有權轉移至s2,s1失效
If you’ve heard the terms shallow copy and deep copy while working with other languages, the concept of copying the pointer, length, and capacity without copying the data probably sounds like making a shallow copy. But because Rust also invalidates the first variable, instead of being called a shallow copy, it’s known as a move. In this example, we would say that
s1
was moved intos2
.
Rust will never automatically create “deep” copies of your data. Therefore, any automatic copying can be assumed to be inexpensive in terms of runtime performance. -
克隆(Clone):
- 顯式深度拷貝堆數據
let s1 = String::from("hello"); let s2 = s1.clone(); // 完整拷貝數據
When you see a call to
clone
, you know that some arbitrary code is being executed and that code may be expensive. It’s a visual indicator that something different is going on.
-
Copy trait:
- 標量類型(整數、布爾值等)自動實現
- 賦值時執行位拷貝而非所有權轉移
- 與Drop trait互斥
引用與借用(Reference & Borrowing)
-
不可變引用:
- 允許多個同時存在
- 禁止修改數據
fn calculate_length(s: &String) -> usize {s.len() }
-
可變引用:
- 獨占性:同一作用域只能存在一個
- 數據競爭預防
fn change(s: &mut String) {s.push_str(", world"); }
懸垂引用問題
懸垂引用(Dangling Reference)是指指針指向的內存已經被釋放但指針仍然存在的情況,這是內存安全的重大威脅。
錯誤示例分析
fn dangle() -> &String { // 嘗試返回字符串引用let s = String::from("hello"); // 創建局部變量&s // 返回局部變量的引用
} // s離開作用域被釋放,返回的引用變成懸垂指針
編譯器會阻止這段代碼編譯,錯誤提示:
error[E0106]: missing lifetime specifier
解決方案
- 轉移所有權
fn no_dangle() -> String { // 直接返回String(轉移所有權)let s = String::from("hello");s // 所有權轉移給調用者
}
- 使用靜態生命周期
fn get_static_str() -> &'static str {"hello" // 字符串字面量有'static生命周期
}
引用安全規則
- 可變性獨占原則:
- 任意時刻,一個數據要么:
- 有唯一的可變引用(&mut T)
- 或有多個不可變引用(&T)
- 二者不可同時存在
- 生命周期保證:
-
所有引用必須始終有效
-
編譯器通過生命周期檢查確保:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y } }
切片(Slice)
- 字符串切片:
- 安全視圖,不獲取所有權
let s = String::from("hello world");let hello = &s[0..5]; let world = &s[6..11];
- 通用原則:
- 編譯時保證引用有效性
- 自動邊界檢查防止越界訪問
內存安全保證
所有權系統在編譯期實現:
- 自動內存回收(RAII模式)
- 無數據競爭
- 無懸垂指針
- 零運行時開銷
這套機制使Rust無需垃圾回收器即可保證內存安全,同時保持與C/C++相當的性能。
The concepts of ownership, borrowing, and slices ensure memory safety in Rust programs at compile time. The Rust language gives you control over your memory usage in the same way as other systems programming languages, but having the owner of data automatically clean up that data when the owner goes out of scope means you don’t have to write and debug extra code to get this control.