以下内容为本人学习过程中的记录笔记,其中可能存在不准确或错误,欢迎勘误及指正
创建闭包
闭包的创建和函数的创建基本一致,但不用使用fn
来定函数。比如下面的main函数中,我们定义了一个闭包
1 2 3 4 5 6 7 8 9
| fn main() { let add = |x: f64, y: f64| -> f64 { println!("{} + {} = {}", x, y, x + y); x + y };
let _result = add(1.0, 2.0); }
|
一般情况下,我们其实可以采用简化语法来创建闭包
1 2 3 4 5 6 7 8 9
| fn main() { let add = |x, y| { println!("{} + {} = {}", x, y, x + y); x + y };
let _result = add(1.0, 2.0); }
|
闭包中的变量类型
在创建和使用闭包时,编译器通常可以直接推断出使用的变量类型而不用自己定义。但需注意的是,变量类型确定后就不能再使用其他类型的变量了
1 2 3 4 5 6
| fn main() { let c = |x| x;
let s = c(String::from("hello")); let n = c(5); }
|
捕获环境
闭包可捕获其所在定义域的环境值,这让闭包的使用比普通函数灵活得多
1 2 3 4 5 6 7 8
| fn main() { let var = 3; let var_add = |x| { println!("{} + {} = {}", x, var, x + var) };
var_add(3); }
|
类似的,如果使用函数的话就不能满足这样的要求了
1 2 3 4 5 6 7 8 9
| fn main() { let var = 3; fn var_add(x: i32) { println!("{} + {} = {}", x, var, x + var) }
var_add(3) }
|
闭包所捕获环境值的所有权
闭包捕获的环境值的所有权和普通函数的所有权保持一致,一共有三种方式
取得变量所有权:FnOnce
满足FnOnce
trait的闭包捕获的环境值只能被闭包调用一次,后续无法再次调用
1 2 3 4 5 6 7 8 9
| fn main() { let name = String::from("rust"); let c = move |greeting: String| (greeting, name);
let result = c("hello".to_string()); println!("result: {:?}", result);
println!("{}", name); }
|
获得变量的可变借用:FnMut
满足FnMut
trait的闭包可以获得环境值的可变借用
1 2 3 4 5 6 7 8 9 10
| fn main() { let mut name = String::from("hello"); let mut c_mut = || { name.push_str(" rust"); println!("c: {}", name); }; c_mut();
println!("{}", name); }
|
获得变量的不可变借用:Fn
满足Fn
trait的闭包不会消耗所捕获环境值的所有权
1 2 3 4 5 6 7 8
| fn main() { let y = String::from("hello"); let closure = |x| { x == y }; println!("{}", closure("hello")); println!("{}", y); }
|
在创建闭包时,Rust可以通过闭包对环境值的使用来推断出闭包具体使用哪个trait,具体而言,即(1)所有的闭包都实现了FnOnce trait
、(2)没有移动捕获变量的实现了FnMut trait
、(3)无需可变访问捕获变量的闭包实现了Fn trait
闭包作为参数
Rust支持函数式编程,所以闭包也可以作为参数、返回值和结构体成员变量。但需注意值的类型是实现Fn
、FnOnce
或者FnMut
trait的类型
作为传入参数
1 2 3 4 5 6 7 8 9 10 11 12
| fn main() { let closure = |x: i32| { println!("print in closure: {}", x); x };
call_closure(closure) }
fn call_closure(closure: impl Fn(i32) -> i32) { closure(10); }
|
作为返回值
1 2 3 4 5 6 7 8 9 10 11
| fn main() { let a = call_closure(); a(1); }
fn call_closure() -> impl Fn(i32) -> i32 { |x: i32| { println!("print in closure: {}", x); x } }
|
作为结构体成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| struct Cacher<T> where T: Fn(i32) -> i32, { calc: T, value: Option<i32>, }
impl<T> Cacher<T> where T: Fn(i32) -> i32, { fn new(clac: T) -> Self { Cacher { calc: clac, value: None, } }
fn value(&mut self, arg: i32) -> i32 { match self.value { Some(v) => v, None => { let v = (self.calc)(arg); self.value = Some(v); v } } } }
fn main() { let mut cacher = Cacher::new(|x| x);
println!("caching: {:?}", cacher.value(2)); }
|