another trend for system-design programming
記錄一下學習 Rust 中的一些技巧:
ownership
在 Rust 中擁有權 (ownership) 是一個跟其他程式不太一樣的概念。不像其他語言在 Rust 中廣泛的區別 Stack 跟 Heap 的使用時機,因為在系統設計 (system design) 中這兩者的效率差異很大。在擁有權下 Rust 訂定的以下三個規則:
- 所有值都有一個變數是他的擁有者
- 一次只有一個擁有者
- 當值離開擁有者的範圍時即刪除
在使用引用 (reference) 時有下面兩個規則:
- 任何時候可以擁有一個可變動的引用 (mutable reference) 或任意數量不可動的引用 (immutable reference)
- 引用必須合法
move / clone / copy
另一個 Rust 不一樣的概念則是變數間的操作。在多數語言中都把值在不同變數間傳遞,在 Rust 的世界稱為 move。在變數間 move 時,如果傳遞的內容為記憶體空間 (絕大多數的 case),則被移動的值就被視為不再使用, 而且 Rust 也不會針對被轉移的變數釋放記憶體 (記憶體已經轉移到新的變數)。
當需要將整體內容轉移到另一個變數而並非只有記憶體位址時,Rust 的世界則是使用 clone
來做深層拷貝
(deep copy)。然而這種操作顯而易見的花費昂貴的記憶體空間與運算時間。而另外一種拷貝則是 copy
,
這是僅限於編譯時期 (compile-time) 知道物件大小使用並不能支援 Drop
這個 trait。
在函數呼叫時變數傳遞僅使用 move 或 copy 來傳遞值,而回傳時則會用 move 回傳變數。在函數結束時,
除非擁有權已經被轉移出去,值會自動被 Drop
刪除。
mutable
另外一個在 Rust 的限制則是 mutable。預設情況下所有的變數在 Rust 中都是唯讀不可改變,當需要改變時,
則需要明確使用 mut
。
在使用上還需要知道拿到的否可更改的值,下面的程式碼顯示 v 拿到的是一個可變動的參照 (reference), 之後 v 可以修改內部的內容但不能修改 v 本身的值。
let v = &mut[(1, 2), (3, 4)];
println!("{:?}", v);
v[0] = (0, -1); // modify the data in reference
println!("{:?}", v);
lifetime
在 rust 的世界裡面所有變數都有生命週期 (lifetime),用來指示參考 (reference) 的引用範圍 (scope)。 在大多數的情空下,生命週期是隱含並可推斷的:程式碼中可以不用明確定義其生命週期 (跟變數型態一樣)。 當 Rust 在編譯時間無法判斷唯一可能的生命週期時,需要額外註釋 (annotate) 其生命週期。 常見的狀況就是引用懸空 (dangling references),也就是引用一個可能會被清空的參考。像是下面則是一個例子:
fn dangling_reference() {
let x;
{
let y = 5;
x = &y;
}
println!("{}", x); // borrow later used here
}
在沒有使用 println!("{}", x)
時程式碼可以正常編譯,但是當加入這行則會跳出 borrow later used here,
代表變數 x
此此時的值是參考 y 的值但已經在此時被消滅。
在資料結構中,可以使用 struct<'a>
宣告生命週期為 a
,其中內部的參照就可以使用相關定義
struct Foo<'a> {
x: &'a i32,
}
super trait
在 trait 定義一個實作標準,讓物件透過實作 (impl) 之後支援特定的函數。
而
supertraits
除了定義 trait 之外,還限制 trait 需要滿足另外一個 trait。
語法是 trait TRAIT : TRAIT ( '+' TRAIT )* { ... }
。