Rust 閉包類型 FnMut -- FnOnce
在這篇短文中,將討論如何使用 FnMut 和 FnOnce 類型的閉包,以及它們之間的區別,並展示一些代碼示例。
首先,閉包的獨特屬性是它能在其聲明的範圍內捕獲上下文環境的變量,而不像在 rust 中的常規函數。閉包以何種方式捕獲環境變量,是由閉包的類型決定的。如 Fn,FnMut 和 FnOnce,Fn 是以不可變的方式捕捉上下文的環境變量,比較簡單。我們在文中討論其他兩個。
FnMut
這個閉包類型可以被調用多次,它以可變的方式捕捉局部變量。重要的是,你不能將可變的值移出閉包,特別是那些沒有實現 Copy trait 的類型。在示例代碼中,我們改變並訪問在閉包外聲明的 Vec,插入一個值作爲參數給閉包,同樣的例子,如果我們將閉包類型從 FnMut 更改爲 Fn(它不可變地借用了上下文變量),編譯器將立即拋出一個警告,不能可變地捕獲上下文變量。
fn take_closure<F>(mut clo: F)
where F: FnMut(u32)
{
clo(12);
clo(13);
}
fn main() {
let mut v = vec![1];
take_closure(|n| v.push(n));
println!("{:?}", v); // [1, 12, 13]
}
FnOnce
FnOnce 類型捕獲上下文環境中變量值的所有權,因爲變量值的所有權已經轉移到閉包中了,所以 FnOnce 類型只能被調用一次,而 Fn 和 FnMut 類型可以調用多次。
修改上面的代碼示例,使用上面提到的 FnOnce 類型從閉包返回 vector,由於我們不能第二次調用閉包,因此拋出錯誤。
fn take_closure<F>(clo: F)
where F: FnOnce(u32) -> Vec<u32>
{
let vec = clo(12);
println!("modified vector is {:?}", vec);
clo(13);
}
fn main() {
let mut v = vec![1];
take_closure(|n| {
v.push(n);
v
});
println!("{:?}", v);
}
編譯錯誤:提示使用了移動後的值。
error[E0382]: use of moved value: `clo`
--> src/main.rs:14:5
|
8 | fn take_closure<F>(clo: F)
| --- move occurs because `clo` has type `F`, which does not implement the `Copy` trait
...
11 | let vec = clo(12);
| ------- `clo` moved due to this call
...
14 | clo(13);
| ^^^ value used here after move
本文翻譯自:
https://medium.com/@raviraj.dj/rusty-shorts-fnmut-fnonce-closures-7b0b8e4defd6
coding 到燈火闌珊 專注於技術分享,包括 Rust、Golang、分佈式架構、雲原生等。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/lqSmB4wnTsieA2XfO237pA