Rust 中的 move 語義
Nilesh Katuwal
2022年6月7日
在本文中,我們將瞭解 Rust 中的移動語義。
在 Rust 中移動語義
在 Rust 中,所有型別都是可變的,所有移動操作都相當於原始資料在新位置的位副本。Move 通過引用或可變引用將任何捕獲的變數轉換為按值捕獲的變數。
當涉及執行緒時,通常使用移動。
Rust 過程也具有破壞性。例如,離開變數後,該變數在程式碼中不再可用。
在 Rust 中,移動始終通過複製物件本身的資料而不破壞原始物件來實現。它永遠不會通過複製物件的託管資源或執行自定義程式碼來實現。
Rust 對不需要移動語義的型別例外。相反,該值包含表示它的所有必要資訊,並且沒有堆分配或資源由該值管理,例如 i32
。
這些型別實現了特殊的 Copy
特徵,因為複製成本低,並且是傳遞給函式或管理分配的預設方法:
fn foo(bar: i32) {
// Implementation
}
let var: i32 = 9;
foo(var); // copy
foo(var); // copy
foo(var); // copy
預設函式呼叫對 Copy
以外的型別(例如 String)使用移動語義。在 Rust 中,當一個變數被移動時,它的生命週期會提前結束。
在編譯時,move 替換了塊末尾的解構函式呼叫,因此為 String 編寫如下程式碼是錯誤的:
fn foo(bar: String) {
// Implementation
}
let var: String = "Hello".to_string();
foo(var); // Move
foo(var); // Compile-Time Error
foo(var); // Compile-Time Error
克隆 rust 需要實現,但對於所有移動都是相同的:複製值中的記憶體並且不呼叫原始值的解構函式。
而在 Rust 中,通過這種精確的實現,所有型別都是可移動的;不可移動型別不存在(儘管不可移動值存在)。位元組必須在新位置編碼有關該值管理的資源的資訊,例如指標,就像它們在先前位置中所做的一樣有效。
Rust 有一種稱為 pinning 的機制,它在型別系統中指示特定值永遠不會再次移動,它可用於實現自引用值並在非同步中使用。
例子:
fn destroy_box(z: Box<i32>) {
println!("The box that contains {} is destroyed", z);
}
fn main() {
let a = 5u32;
let b = a;
println!("a is {}, and y is {}", a, b);
let m = Box::new(5i32);
println!("a contains: {}", m);
let n = m;
destroy_box(n);
}
destroy_box
函式獲取上述原始碼中堆分配記憶體的所有權。首先,z
被銷燬,記憶體被釋放。
m
是指向堆分配整數的指標。
輸出:
a is 5, and y is 5
a contains: 5
The box that contains 5 is destroyed