🦀 Rust 所有權機制
📚 目錄
- 什么是值類型和引用類型?值語義和引用語義?
- 什么是所有權?為什么 Rust 需要它?
- 所有權的三大原則(修正版)
- 移動語義 vs 復制語義:變量賦值到底發生了什么?
- 綁定和作用域:值的“活多久”與“誰管它”
- 引用和借用:本質是什么?為什么這么設計?
- 借用的三條規則(逐條解釋+示例)
- 生命周期:引用能用多久?
- 生命周期參數:為什么需要?怎么用?
- Rust 的借用檢查器是怎么幫你“兜底”的?
- 總結與學習建議
1?? 什么是值類型和引用類型?值語義和引用語義?
?? 值類型(Value Type)
變量里存的是實際的數據。
let x = 10; // x 是 i32 值類型
?? 引用類型(Reference Type)
變量里存的是指向其他數據的“地址”。
let x = 10;
let y = &x; // y 是對 x 的引用,類型是 &i32
🔍 值語義 vs 引用語義
概念 | 解釋 | 示例 |
---|---|---|
值語義 | 每次賦值都復制/移動數據本身 | let b = a; |
引用語義 | 多個變量共享同一個值的訪問權(指針) | let r = &a; |
2?? 什么是所有權?為什么 Rust 需要它?
在 Rust 中,所有權機制用于管理內存,確保內存安全,不靠垃圾回收(GC),也不手動 free
。
通俗理解:誰擁有這個數據,誰負責清理它。
- 避免懸空引用
- 自動釋放資源(變量離開作用域)
- 避免多線程數據競爭
3?? Rust 所有權的三大原則
- 每個值在任意時刻只能有一個所有者。
- 當所有者離開作用域,值會被自動釋放。
- 一個值只能有一個可變引用,或任意多個不可變引用,但不能同時存在。
let a = String::from("hello");
let b = a; // a 的所有權移動到 b
// println!("{}", a); // ? 報錯:a 被移動了
4?? 移動語義 vs 復制語義
let a = 10; // a 是 Copy 類型
let b = a; // 自動復制,a 仍然有效let s1 = String::from("Hi");
let s2 = s1; // 所有權移動,s1 失效
想要深拷貝,用 .clone()
:
let s1 = String::from("Rust");
let s2 = s1.clone(); // ? s1 仍有效
5?? 綁定和作用域
變量只在其“作用域”內有效:
{let name = String::from("Tom");println!("{}", name);
} // name 離開作用域,自動釋放
作用域由 {}
包圍,函數、if、match、循環等都會創建作用域。
6?? 引用和借用:到底有什么區別?
? 本質解釋:
- 引用(reference)是“變量的地址”(通過
&
獲取) - 借用(borrowing)是“使用別人的值但不擁有它”的行為
🧠 所以:“引用”是工具,而“借用”是動作。
舉例說明:
let s = String::from("Rust");
let r = &s; // 你用 &s 創建了一個“引用”,這就是“借用了 s 的值”
概念 | 通俗解釋 | Rust 表現形式 |
---|---|---|
引用 | 地址 | &a 、&mut a |
借用 | 臨時借東西不擁有 | let r = &a |
7?? 借用的三條規則(逐條解釋+示例)
規則 1:借用不能比原值活得更久(生命周期限制)
fn dangle() -> &String {let s = String::from("oops");&s // ? s 被釋放,引用懸空
}
規則 2:可變借用具有獨占性
let mut s = String::from("hi");
let r1 = &mut s;
// let r2 = &mut s; // ? 同時只能有一個可變借用
規則 3:有不可變借用時,不能再借出可變引用
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
// let r3 = &mut s; // ? 報錯:不能混合借用
📌 原則:只讀可以多個,可寫只能一個,不能混用。
8?? 生命周期:引用能用多久?
生命周期就是引用在內存中能活多久。
Rust 不允許引用指向已釋放的內存:
fn dangle() -> &String {let s = String::from("hi");&s // ? 返回了已經釋放的 s
}
9?? 生命周期參數:為什么需要?怎么用?
當函數的參數和返回值中有引用,Rust 要你說明它們“誰活得久”。這就是“生命周期參數”。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }
}
解釋:
<'a>
是生命周期參數x
、y
、返回值 都必須活得跟'a
一樣久
📌 一般來說,編譯器可以自動推斷。但在函數返回引用時,必須顯式寫出生命周期參數。
🔟 Rust 的借用檢查器是怎么幫你的?
Rust 有一個非常強大的“借用檢查器”(Borrow Checker),會在編譯階段檢查:
- 有沒有懸空引用?
- 可變引用有沒有被別名?
- 是否混用了可變和不可變引用?
- 生命周期是否符合規則?
🧠 你寫錯了引用規則,Rust 不會讓你運行,而是直接編譯失敗。
? 借用檢查器就是 Rust 安全的“守門員”!它會嚴格替你把關內存安全。
🔚 總結與學習建議
概念 | 通俗解釋 |
---|---|
所有權 | 誰擁有值,誰負責清理 |
移動 | 所有權轉移,原值失效 |
復制 | 創建副本,兩個變量互不影響 |
借用 | 臨時訪問但不擁有,分可變/不可變 |
引用 | 表示地址,借用的語法工具 |
生命周期 | 引用能活多久(不能活得比原值久) |
生命周期參數 | 顯式告訴編譯器“誰和誰一樣久” |
!