閉包是一個可捕獲周圍環境的可執行代碼片段,基本的幾個定義方式如下:
fn add_one_v1 (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
| |內部的是捕獲的周圍的變量,默認捕獲的是不可變借用,先給出一個實際代碼片段:
use std::thread;
use std::time::Duration;
fn main() {
let foo = |num| { // 定義一個閉包,捕獲一個變量
thread::sleep(Duration::from_millis(num));
println!("sleep for {} milliseconds", num);
};
let num = 200;
foo(num);
}
注意:閉包一般不必顯式聲明變量的類型,但是閉包只能推斷一種類型的數據,再次出現其它類型的數據時會報錯。 給出代碼説明:
fn main() {
let foo = |x| x;
foo(1.1);
foo("foo".to_string()); // 這裏會報錯,第一次推斷的時候,就已經明確這是f32的類型看了
}
如果我們想讓閉包在第一次調用時就保存好結果,之後返回第一次計算的結果,可以使用緩存的機制,下面代碼給出一般的緩存機制。但是,這個機制存在一個問題,如果第一次有了計算結果了,那麼再次傳入新的值,返回的也是第一次計算的結果。
struct Cache<T>
where T: Fn(u32) -> u32 // 注意這裏閉包聲明的方式
{
calculation: T,
value: Option<u32>
}
impl<T> Cache<T>
where T: Fn(u32) -> u32
{
fn new(calculation: T) -> Cache<T> {
Cache {
calculation,
value: None
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
},
}
}
}
fn main() {
let mut res = Cache::new(|num| {
num * num
});
let v1 = res.value(2);
let v2 = res.value(10); // 這仍然會返回之前的結果
println!("v1 = {}, v2 = {}", v1, v2); // v1 = 4, v2 = 4
}
如果想要根據不同的值計算結果,可以利用HashMap等的思路。
閉包三種捕獲方式,附帶3種聲明方式:
FnOnce消費從周圍作用域捕獲的變量,閉包周圍的作用域被稱為其 環境,environment。為了消費捕獲到的變量,閉包必須獲取其所有權並在定義閉包時將其移動進閉包。其名稱的 Once 部分代表了閉包不能多次獲取相同變量的所有權的事實,所以它只能被調用一次。FnMut獲取可變的借用值所以可以改變其環境Fn從其環境獲取不可變的借用值
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。