iT邦幫忙

1

二、三天學一點點 Rust:來! 擁有權Ownership之四(20)

  • 分享至 

  • xImage
  •  

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 擁有複製後的資料。
  • 這不同於一般的變數賦值(會產生 move),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() 成本較高,但在處理 StringVec 等堆積資料時是非常實用且必要的技巧。既然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);
}

✅ 程式說明:& 借用(Borrowing)與參照(Reference)

  1. let my_heap_value = String::from("Jack"); 創建一個 String 物件,my_heap_value 擁有這個字串的所有權。字串的資料儲存在堆積上.
  2. let my_heap_reference = &my_heap_value; 使用 & 符號建立一個不可變參照(immutable reference),它借用而非擁有原始資料。
  3. println!() 中同時使用 my_heap_valuemy_heap_reference 是合法的,因為只存在不可變參照。

🔍 &T 是 Rust 中的「reference type(參照型別)」,它指向某個值而不擁有該值。


🧠 課堂觀念整合

📌 References must never outlive their referent: 這句話的意思是,reference 的生命週期不能比它所指向的資料的生命週期長。如果 reference 比它指向的資料活得更久,那麼 reference 就會指向無效的記憶體,這會導致錯誤。也就是說:

  • referent 是原始的被參照資料(這裡是 my_heap_value)。
  • reference 是用 & 建立的指針(這裡是 my_heap_reference)。
  • Rust 編譯器會保證引用不會在原始值釋放(drop)之後還繼續存活,這就是為什麼 Rust 的參照是「安全」的。

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


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言