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
的全部權語義,即不能同時存在多個可變引用。