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(解引用強制轉換)。最主要也是能夠更簡潔易讀。