Rust 中的闭包(closure),也叫做 lambda 表达式或者 lambda,是一类能够捕获周围作用域中变量的函数。
闭包允许变量捕获(capture)灵活地适应使用场合,既可移动(move)又可 借用(borrow)变量。闭包可以通过以下手段捕获变量:
Fn 通过引用: &T
FnMut通过可变引用: &mut T
FnOnce通过值: T
译注:顺序之所以是这样,是因为 : &T 只是获取了不可变的引用, &mut T 则可以改变变量, T 则是拿到了变量的所有权而非借用。
use std::mem; fn main() { let color = "green"; let print = ||println!("color: {}", color); print(); print(); let moveable = Box::new(3); let consume = ||{ println!("moveable: {:?}",moveable); mem::drop(moveable); }; consume(); // 只能运行一次,不可复制类型(在堆上申请空间的数据类型)必须移动(move)到闭包中 let stack = vec![1,2,3,4,5]; let contains = move |needle|stack.contains(needle); println!("向量stack的容量是否包含1:=>{}",contains(&1)); println!("向量stack的容量是否包含6:=>{}",contains(&6)); } // color: green // color: green // moveable: 3 // 向量stack的容量是否包含1:=>true // 向量stack的容量是否包含6:=>false示例二 以下的示例,将函数(闭包)作为参数传入函数中。
use std::mem; //该函数将闭包作为参数并调用它 fn apply<F>(f:F) where //闭包没有输入值和返回值 F:FnOnce(){ f(); } fn apply_to_3<F>(f:F)->i32 where F: Fn(i32) ->i32{ f(3) } fn main() { let greeting = "hello"; let mut farewell = "goodbye".to_owned(); let diary = ||{ println!("I said {}.",greeting); // `greeting`通过引用捕获,故需要闭包是`Fn` farewell.push_str("!!!"); // 改变了`farewell`,闭包通过可变引用来捕获它,需要`FnMut`。 println!("Then I screamed {}.",farewell); mem::drop(farewell); //手动调用drop,闭包通过值获取`farewell`(包括所有权)。需要`FnOnce` }; apply(diary); let double = |x| {2*x}; println!("3 double: {}",apply_to_3(double)); } // I said hello. // Then I screamed goodbye!!!. // 3 double: 6目前 Rust 只支持返回具体(非泛型)的类型。 按照定义,匿名的闭包的类型是未知的,所以只有使用 impl Trait 才能返回一个闭包。
必须使用 move 关键字(捕获都是通过值进行),因为在函数退出时,任何通过引用的捕获都被丢弃,防止在闭包中留下无效的引用。
示例(返回闭包(函数))
fn create_fn() ->impl Fn(){ let text = "zhangsan".to_owned(); move||println!("This is a {}",text) } fn create_fnmut()-> impl FnMut(){ let text = "lisi".to_owned(); move||println!("This is a {}",text) } fn main() { let fn_plain = create_fn(); let mut fn_mut = create_fnmut(); fn_plain(); fn_mut(); }