rust中定义函数签名是显式制定的,保证了编译器的检查数组
let example = demo;
let c: fn(&str)->bool= example; // fn pointer type
assert_eq!(0,std::mem::size_of_val(&example));
assert_eq!(8,std::mem::size_of_val(&c));
复制代码
闭包能够捕获环境中的自由变量,这一点弥补了函数的缺陷markdown
fn fiber(x: i32)-> fn(i32)-> i32{
fn add(y: i32)-> i32{
x+y // error[E0434]: can't capture dynamic environment in a fn item
}
add
}
fn main() {
let f1 = fiber(1);
assert_eq!(2,f1(1));// help: use the `|| { ... }` closure form instead
}
复制代码
闭包的使用方法以下:闭包
fn fiber(x: i32) -> impl FnMut(i32)-> i32 {
move |y| x+y
}
fn main() {
assert_eq!(2,fiber(1)(1));
}
复制代码
rust
中闭包的实现原理:rust全部权语义的核心理念能够归结为“可变不共享,共享不可变”的规则函数
---《深刻浅出rust》优化
即:ui
FnOnce
的trait
FnMut
Fn
的trait
特殊状况:spa
FnOnce
看成fn(T)
函数指针看待。Fn
->FnMut
->FnOnce
三者的关系是依次继承。#![feature(unboxed_closures, fn_traits)]
struct Closure{
env_car: i32
}
impl FnOnce<()> for Closure{
type Output = ();
#[warn(unused_variables)]
extern "rust-call" fn call_once(self, args: () ) -> (){
println!("FnOnce{}",self.env_car)
}
}
impl FnMut<()> for Closure{
extern "rust-call" fn call_mut(&mut self, args: () ) ->(){
println!("可变引用FnMut{}",self.env_car)
}
}
impl Fn<()> for Closure{
extern "rust-call" fn call(&self, args: () ) -> (){
println!("不可变引用Fn{}",self.env_car)
}
}
fn main() {
let demo = 1;
let c = Closure {
env_car: demo
};
c.call(())
}
复制代码
若是要在函数内返回一个闭包,须要用到move
关键字,这样会捕获函数内部变量,并转移该变量的全部权。若是是Sring
类型这种没有实现Copy
语义的类型,将不能捕获,move
也会失效。这两种状况的闭包分别称为逃逸闭包和非逃逸闭包。指针
根据全部权的语义,不可变引用是能够同时存在多个的,可是在闭包里有一种状况只能存在惟一的不可变引用:code
let mut a = [1,2,3];
let x = &mut a;
{
let mut c = || {(*x)[0] = 0;};
let y = &x; // 报错 second borrow occurs here
c();
}
let z = &x; //ok
复制代码
在上面的代码里先定义一个固定长度的数组,接着取a
的可变借用x
,而后在一个表达式内部定义c
是一个闭包,这个闭包的做用是将a
的第一个元素修改成0
,接着再取x
的解引用,这里编译器报错显示cannot borrow x because previous closure reuqires unique access
,意思是第一次的索引已经存在了x
的不可变引用(隐式),对于x
的第二次借用编译器便不容许对于闭包捕获变量的第二次不可变借用。orm
trait
做为rust
的核心,闭包又实现了哪些trait
呢
Sized
的trait
。Copy
的trait
,而且以可变引用的方式修改它,这样闭包就不会有Copy
trait。Move
语义,且闭包内有修改或者消耗该变量,则闭包不会有Copy
trait。以上的三点其实也都对应了rust
的全部权语义,即不能同时存在多个可变引用。