闭包
闭包在RUST 种被定义为一个类型,该类型实现了特定的 特征;
闭包也是一个表达式,关于表达式和语句 我们已经介绍过了
闭包的使用类似于函数的调用,但是闭包可以捕获当前作用域内的变量
闭包基本语法
(move) || expression, 其中 ||用来声明入参
fn func<T, F: FnOnce(T)-> T, > (val: T , f: F) -> T{
f(val)
}
fn double_func<T: std::ops::Mul<i32, Output = T>>(val:T) -> T {
val*2
}
fn main() {
let double = |x| x * 2; //闭包可以作为变量绑定
let doubled = double(10); // 通过变量 调用闭包
let doubled = func(10, |x| x*2); //闭包作为参数传递
println!("{}",doubled);
let doubled = func(10, double_func); //函数作为参数传递
println!("{}",doubled);
}
上述用法,基本上和函数使用是一样的,但是闭包最重要的功能是 闭包的语句能够捕获(使用)当前作用域内的变量
fn create_error() -> Result<(),String> {
Err("invalid param".to_string())
}
fn main() {
let str_prefix = "main module: ";
let result = create_error().map_err(|mut err| format!("{} {}",str_prefix, err));
println!("{:?}",result)
}
在传递给map_err的闭包函数种,我们定义了入参 mut err,但是我们也在表达式中用到了 str_prefix,该变量作用域是在当前main的作用域
如果使用函数实现类似功能,则无法像这样使用,必须要把 str_prefix 传递出去才可以
闭包类型探讨
本小节我们尝试透过闭包类型,来看闭包是如何实现 作用域参数捕获的
在前一个小节的例子中,当我们定义了闭包时,类似的会生成这样一个类型
struct Closure<'a> {
s : &'a str,
}
impl<'a> FnOnce<(String)> for Closure<'a> {
type Output = String;
fn call_once(self, err: String) -> String {
format!("{} {}",self.s, err)
}
}
//这里类似于:let clousre = Closure{s: str_prefix};
// create_error().map_err(clousre);
let result = create_error().map_err(|mut err| format!("{} {}",str_prefix, err));
pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, F> {
match self {
Ok(t) => Ok(t),
Err(e) => Err(op(e)), //这里类似会发生 op.call_once(e);
}
}
通过上述对于闭包的展开,我们知道 闭包对于作用域内变量使用,其实是在定义闭包类型是 初始化为闭包结构体的元素
闭包的捕获方式
闭包对作用域内的变量有多种使用方式
- 所有权移动: 一旦闭包涉及移动作用域内变量所有权,则闭包只能使用一次;且后续该变量无法继续使用
- 可用借用:在闭包作用期间,需要符合借用规则 可以多次调用
- 不可变借用: 在闭包作用期间,需要符合借用规则 可以多次调用
- 不使用变量: 行为等于函数
上述不同行为,分别对应的不同特征的方法
pub trait FnOnce<Args>
where
Args: Tuple,
{
type Output;
// Required method
extern "rust-call" fn call_once(self, args: Args) -> Self::Output; //闭包使用过后,无法在使用
}
pub trait FnMut<Args>: FnOnce<Args>
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call_mut(
&mut self,
args: Args
) -> Self::Output; //闭包使用可变引用,可以重复调用
}
pub trait Fn<Args>: FnMut<Args>
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call(&self, args: Args) -> Self::Output; //闭包使用不可变引用,可以重复调用
}