[英]Situations where a move to a function is actually wanted in Rust
我想確定哪些一般(或特定)情況不希望使用引用將對象傳遞給Rust中的函數。
我最感興趣的是功能 (例如,一個函數是為了清理移入其中的資源),但是性能原因也很有趣(例如,如果復制一個小結構比訪問它更快)通過指針)。
當然,這涉及非Copy
類型。
注意:很清楚為什么在分配中使用移動語義,以防止混疊,例如,但在功能中不會出現問題。
在某些情況下,所有這些都與結構的生命周期有關,即我正在編寫Octavo(加密庫),其中我們有一些哈希函數(即SHA1):
let mut digest = SHA1::new();
digest.update("Ala ma kota!");
let result = digest.result(); // here we invalidate digest as it finished its work
以上情況的其他用法是構建器模式:
PizzaBuilder::new()
.add_sauce()
.add_cheese()
.add_topping(Topping::Tomato)
.add_topping(Topping::Bacon)
.add_topping(Topping::Jalapenio)
.bake() // here we destroy PizzaBuilder as this setup isn't usable anymore
// you should create new PizzaBuilder for another pizza
// (you cannot reuse dough once you bake pizza)
考慮轉換函數fn(T) -> U
如果通過引用獲取T
則需要在U
上的所有操作來維持T
的不變量。 這意味着不允許任何人以任何方式摧毀T
此外,呼叫者將負責保持輸入到位以使U
保持有效。 一個很好的例子是Vec::into_boxed_slice
。
另一個例子是移動其輸入的函數。 顯然,這不能接受一個&mut
而沒有令人擔憂的語義。 一個例子是Vec::insert
。
另一個選擇是什么時候&mut Trait: Trait
。 在這種情況下,使用T: Trait
允許調用者決定是否使用動態調度或傳遞參數進行借用,這些參數具有易於使用(在兩個方向上),速度和代碼膨脹的分支。
另一個例子可能只是對常見情況的方便語法的偏好,其中克隆是便宜的。 一個例子可能是Vec
Index<Range<usize>>
。
如果要限制在給定對象上調用函數的次數,還有令人信服的安全性原因。 最簡單的例子是drop
,你只能調用一次。 一個非常奇特的例子是用於頻道通信的“會話類型”。
移動語義的一個應用是類型安全的狀態機。 假設您有一個可以處於兩種狀態的對象,未初始化和初始化,並且從未初始化到初始化具有副作用,並且可能會失敗。 這自然地用兩種類型建模,其中一種轉換方法通過值接受第一種類型的對象並返回第二種類型的對象:
pub struct UninitFoo {
...
}
impl UninitFoo {
pub fn new() -> UninitFoo { ... }
pub fn configure_something(&mut self) { ... }
pub fn configure_something else(&mut self) { ... }
pub fn initialize(self) -> Result<InitFoo, SomeError> { ... }
}
pub struct InitFoo {
...
}
impl InitFoo {
pub fn do_some_work(&mut self) { ... }
}
上面的例子真是做作,但我想你明白了。 這樣,您的類型集基本上形成狀態機,其中initialize()
等方法是狀態之間的轉換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.