iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0
Rust

Rust 逼我成為更好的工程師:從 Borrow Checker 看軟體設計系列 第 5

(Day5) Rust Copy 與 Clone 零成本 vs 有成本複製

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250917/20124462KA2M7PfuNm.png

Rust 逼我成為更好的工程師:Copy 與 Clone - 零成本 vs 有成本複製

在理解了所有權的移動 (Move) 和借用 (Borrow) 之後,我們來探討一些真實世界中更細膩的情境。

為什麼 i32 不會像 String 一樣被「移走」?

如何設計出更優雅、更高效的函式?以及,當借用規則變得複雜時,編譯器如何像一位良師益友般引導我們?

Copy 與 Clone:所有權轉移的例外規則

看到這裡你可能會想:難道每次傳遞一個 i32 整數給函式,原來的變數也會失效嗎?
這就引出了 Move 語義的一個重要例外:Copy Trait。

當一個變數被傳遞時,編譯器會根據其型別是否實現 Copy Trait 來決定採取哪種行為。

https://ithelp.ithome.com.tw/upload/images/20250919/20124462m5nKPpFPZS.png

Copy 型別:廉價的自動複製

fn take_number(x: i32) {
    println!("函式內部: {}", x);
}

fn main() {
    let x = 5;
    take_number(x);  // x 的值被「複製」給函式,不是移動
    println!("x: {}", x);  // ✅ x 仍然有效!
}

對於實現了 Copy 的型別(如 i32f64bool 等),「= 」和函式參數傳遞都是複製,而不是移動

為什麼這些型別可以自動複製?

因為它們的資料完全儲存在堆疊 (stack) 上,大小固定,複製的成本極低。

只是一次記憶體位元的直接拷貝 (bitwise copy)。

它們不擁有任何堆 (heap) 上的資源,所以複製它們不會產生「有兩個擁有者指向同一份堆資料」的混亂情況。

一個重要的規則是:只有當一個型別的所有成員也都是 Copy 型別時,這個型別本身才能被標記為 Copy
這就是為什麼包含 StringVecstruct 不能是 Copy 型別。
https://ithelp.ithome.com.tw/upload/images/20250919/20124462KymVNtGuIW.png

Clone 型別:昂貴的顯式複製

對於沒有實現 Copy 的型別(StringVec 等),它們管理著堆上的資源,複製成本較高。

因此,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 仍然有效
}

https://ithelp.ithome.com.tw/upload/images/20250919/20124462VJdt6QfmaJ.png

總結

CopyClone 是 Rust 所有權系統中處理「複製」的核心概念,它們讓 API 設計更具意圖性與效率:

  1. Copy:無感知的廉價複製

    • 適用於完全儲存在堆疊 (stack) 上的簡單型別,如 i32, bool, char 等。

    • 複製成本極低(只是位元拷貝),因此 Rust 會自動、隱式地進行複製,而不是移動。

    • 讓這些基礎型別的行為符合開發者直覺,無需擔心所有權轉移問題。

  2. Clone:有意識的昂貴複製

    • 適用於擁有堆 (heap) 上資源的複雜型別,如 String, Vec

    • 複製意味著需要配置新的堆記憶體並拷貝資料,成本較高。

    • 為了避免意外的效能損耗,Rust 要求必須手動、顯式地呼叫 .clone() 方法來進行深層複製。

透過區分這兩種行為,Rust 的編譯器強迫開發者在編寫程式時思考:「這裡的資料是廉價的複製,還是昂貴的複製?」

這種思考模式有助於我們設計出更高效、更安全的 API,從源頭上避免不必要的效能問題與所有權混淆。

Copy vs Clone 的區別:

特性 Copy Clone
觸發時機 自動 手動
成本 零成本 有成本
適用類型 基本類型 所有類型
語法 let y = x; let y = x.clone();

相關資源參考

Rust 官方文件


上一篇
(Day4) Rust 所有權與借用的交錯:一個變數的歷程
系列文
Rust 逼我成為更好的工程師:從 Borrow Checker 看軟體設計5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言