clone() 與擁有權(Ownership)關係當你明確想要複製資料時,會使用 clone,這對於像 String 這樣的型別來說至關重要,當你需要同一個資料擁有多個獨立的所有者時。而clone 方法則用於在堆積上建立資料的深層複製。
fn main() {
let person = String::from("Roger");
let genious = person.clone();
println!("{}", person);
println!("{}", genious);
}
String::from("Roger") 建立了一個擁有堆積資料的 String。clone() 會產生一份全新的副本,**深層複製(deep copy)**堆積中的資料。person 保有原來的所有權,新變數 genious 擁有複製後的資料。clone() 明確複製資料,因此兩變數都能安全使用。clone() 與 Copy 的差異比較| 比較項目 | Copy(如 i32) |
clone()(如 String) |
|---|---|---|
| 複製內容 | 位元複製(shallow) | 深層複製(deep copy) |
| 適用型別 | 簡單型別(stack-only) | 堆積型別(如 String、Vec) |
| 實作方式 | 自動由編譯器處理 | 呼叫 .clone() 明確執行 |
| 成本效能 | 幾乎無成本 | 有成本(堆積記憶體重新分配) |
| 所有權是否轉移 | 不會 | 不會(兩者都有各自的所有權) |
📚 參考文件:std::clone::Clone - Rust Docs
| 行為類型 | 說明 |
|---|---|
| Move | 移轉所有權,原變數無法再使用 |
| Copy | 位元複製,適用於固定大小、簡單型別 |
| Clone | 深層複製,適用於堆積資料型別,兩個變數各自有所有權 |
使用 .clone() 是在 Rust 中避免 move 而想要保留原始變數時的一種安全手段。雖然 clone() 成本較高,但在處理 String、Vec 等堆積資料時是非常實用且必要的技巧。既然clone成本高,那有成本不高的嗎?接著我們就來討論Borrowing、reference和擁有權的關係。
& Borrowing、Reference 與 Ownership 的關係以下程式碼展示了 Rust 中的 Borrowing(借用)、Reference(參照)與 Ownership(擁有權)之間的關係:
fn main() {
let my_heap_value = String::from("Jack");
let my_heap_reference = &my_heap_value;
println!("{}\n{}", my_heap_value, my_heap_reference);
}
let my_heap_value = String::from("Jack"); 創建一個 String 物件,my_heap_value 擁有這個字串的所有權。字串的資料儲存在堆積上.let my_heap_reference = &my_heap_value; 使用 & 符號建立一個不可變參照(immutable reference),它借用而非擁有原始資料。println!() 中同時使用 my_heap_value 和 my_heap_reference 是合法的,因為只存在不可變參照。🔍
&T是 Rust 中的「reference type(參照型別)」,它指向某個值而不擁有該值。
📌 References must never outlive their referent: 這句話的意思是,reference 的生命週期不能比它所指向的資料的生命週期長。如果 reference 比它指向的資料活得更久,那麼 reference 就會指向無效的記憶體,這會導致錯誤。也就是說:
referent 是原始的被參照資料(這裡是 my_heap_value)。reference 是用 & 建立的指針(這裡是 my_heap_reference)。🧹 my_heap_value 才是擁有者。:
my_heap_reference 是一個「借來」的引用,它本身不擁有資料,因此當 my_heap_reference 離開作用域時,只有 reference 本身會被清理,但堆積上的字串 "Jack" 不會被清除。my_heap_value 才是字串的所有者。當 my_heap_value 離開作用域時,字串的記憶體才會被釋放。| 名稱 | 說明 |
|---|---|
| Ownership(擁有權) | 誰負責釋放記憶體(只有一個 owner) |
| Borrowing(借用) | 建立對資料的參照,但不擁有,透過 & 建立 |
| Reference(參照) | 是借用後的變數,實際是指向記憶體位址的安全指標 |
| Referent(被參照者) | 原始值,例如 String::from("Jack") 所產生的變數 |
| Drop 順序 | 先釋放引用 → 最後釋放擁有者 → 才真正清掉堆積資料 |
📚 參考文件:The Rust Book - References and Borrowing
Rust 中的 & 建立的是「安全的指標」,稱為 reference(參照),它會借用原始值但不擁有,並且不能超出被參照值的生命週期。這樣的設計讓 Rust 能夠保證記憶體安全,又不需要垃圾回收機制。
println!("{}\n{}", my_heap_value, *my_heap_reference);
在前述的程式碼中,*my_heap_reference前面加了一個 *,這個稱之為「解引用運算符」,此運算符用於解引用(dereference)一個 reference(引用)。 當你對一個 reference 使用 * 時,你實際上是在存取 reference 所指向的記憶體位置的值。
但你也會心想即使你不寫 *my_heap_reference ,程式碼通常也能夠正確印出 my_heap_reference 的值啊!
這是因為 Rust 能夠「聰明地」將 &String 「強制轉換」為 String,以便 println! 可以使用它。這個過程就稱之為 deref coercion(解引用強制轉換)。最主要也是能夠更簡潔易讀。