
在理解了所有權的移動 (Move) 和借用 (Borrow) 之後,我們來探討一些真實世界中更細膩的情境。
為什麼 i32 不會像 String 一樣被「移走」?
如何設計出更優雅、更高效的函式?以及,當借用規則變得複雜時,編譯器如何像一位良師益友般引導我們?
看到這裡你可能會想:難道每次傳遞一個 i32 整數給函式,原來的變數也會失效嗎?
這就引出了 Move 語義的一個重要例外:Copy Trait。
當一個變數被傳遞時,編譯器會根據其型別是否實現 Copy Trait 來決定採取哪種行為。

fn take_number(x: i32) {
println!("函式內部: {}", x);
}
fn main() {
let x = 5;
take_number(x); // x 的值被「複製」給函式,不是移動
println!("x: {}", x); // ✅ x 仍然有效!
}
對於實現了 Copy 的型別(如 i32、f64、bool 等),「= 」和函式參數傳遞都是複製,而不是移動。
為什麼這些型別可以自動複製?
因為它們的資料完全儲存在堆疊 (stack) 上,大小固定,複製的成本極低。
只是一次記憶體位元的直接拷貝 (bitwise copy)。
它們不擁有任何堆 (heap) 上的資源,所以複製它們不會產生「有兩個擁有者指向同一份堆資料」的混亂情況。
一個重要的規則是:只有當一個型別的所有成員也都是
Copy型別時,這個型別本身才能被標記為Copy。
這就是為什麼包含String或Vec的struct不能是Copy型別。
對於沒有實現 Copy 的型別(String、Vec 等),它們管理著堆上的資源,複製成本較高。
因此,Rust 要求你必須手動、顯式地調用 .clone() 方法來進行深層複製。
fn take_string(s: String) {
println!("函式內部: {}", s);
}
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone(); // 顯式複製
take_string(s1); // s1 被移動
println!("s2: {}", s2); // ✅ s2 仍然有效
}

Copy 和 Clone 是 Rust 所有權系統中處理「複製」的核心概念,它們讓 API 設計更具意圖性與效率:
Copy:無感知的廉價複製
適用於完全儲存在堆疊 (stack) 上的簡單型別,如 i32, bool, char 等。
複製成本極低(只是位元拷貝),因此 Rust 會自動、隱式地進行複製,而不是移動。
讓這些基礎型別的行為符合開發者直覺,無需擔心所有權轉移問題。
Clone:有意識的昂貴複製
適用於擁有堆 (heap) 上資源的複雜型別,如 String, Vec。
複製意味著需要配置新的堆記憶體並拷貝資料,成本較高。
為了避免意外的效能損耗,Rust 要求必須手動、顯式地呼叫 .clone() 方法來進行深層複製。
透過區分這兩種行為,Rust 的編譯器強迫開發者在編寫程式時思考:「這裡的資料是廉價的複製,還是昂貴的複製?」
這種思考模式有助於我們設計出更高效、更安全的 API,從源頭上避免不必要的效能問題與所有權混淆。
Copy vs Clone 的區別:
| 特性 | Copy | Clone |
|---|---|---|
| 觸發時機 | 自動 | 手動 |
| 成本 | 零成本 | 有成本 |
| 適用類型 | 基本類型 | 所有類型 |
| 語法 | let y = x; |
let y = x.clone(); |