从网上摘录了一些Fn,FnMut,FnOnce的说明,具体可以看看这个链接,不过这个是在rust 1.0之前写的,有些东西过时了
http://smallcultfollowing.com/babysteps/blog/2014/11/26/purging-proc/
这个是以前的Fn,FnMut,FnOnce的声明,现在1.2.0已经改变了,不过这个更好理解:
trait Fn<A,R> { fn call(&self, args: A) -> R };
trait FnMut<A,R> { fn call_mut(&mut self, args: A) -> R };
trait FnOnce<A,R> { fn call_once(self, args: A) -> R };
这3个trait的区别就在于self的区别,他们对应了3种不同的函数调用:
- Fn类似于shared reference,closure不可以改变环境变量
- FnMut类似于mutable reference,closure可以改变环境变量
- FnOnce类似于ownership,closure只能调用一次
我们还要知道Fn,FnOnce,FnMut这3个trait的语法糖形式:
FnMut(&String) -> uint
这个对应了:
<'a> FnMut<(&'a String,), uint>
知道了这个语法糖下面的代码就比较容易理解了,Foo将实现了trait Fn(i32)->i32的函数或者closure保存在成员变量func里,需要调用的时候通过(self.func)(xxx);的形式调用,注意(self.func)要用括号,不然编译器会把self.func单做是impl实现的method
//F是满足Fn(i32)->i32这个trait的所有closure,函数和struct的static函数
struct Foo<F:Fn(i32)->i32> {
func: F,
data:i32
}
impl<F:Fn(i32)->i32> Foo<F> {
fn new(f:F)->Foo<F>{
Foo{func:f,data:3}
}
fn print(&self){
println!("data:{}", self.data);
//注意调用方式类似于c++的函数指针,self.func要用()再调用
println!("result of func:{}", (self.func)(3));
}
fn calc(&mut self,i:i32){
self.data = (self.func)(5) + i;
}
}
//Bar
struct Bar;
impl Bar {
fn calc(&self,i:i32)->i32{
i+5
}
fn calc_static(i:i32)->i32{
i+7
}
}
//func
fn func(i: i32) -> i32 {
i+6
}
//main
fn main() {
let f1 = Foo::new(|i|i+3);
f1.print();
let f2 = Foo::new(Bar::calc_static);
f2.print();
//Fn(i32)->i32只能用于匹配函数,closure和struct的static 函数
// let b1 = Bar;
// let f3 = Foo::new(b1.calc);
// f3.print();
let f4 = Foo::new(func);
f4.print();
}