高阶函数
高阶函数
高阶函数与普通函数的不同在于,它可以使用一个或多个函数作为参数,可以将函数作为返回值。
函数类型
关键字
The function type constructor fn forms new function types. A function type consists of a possibly-empty set of function-type modifiers (such as unsafe or extern), a sequence of input types and an output type.
fn inc(n: i32) -> i32 {//函数定义
n + 1
}
type IncType = fn(i32) -> i32;//函数类型
fn main() {
let func: IncType = inc;
println!("3 + 1 = {}", func(3));
}
上例首先使用fn
定义了inc
函数,它有一个i32
类型参数,返回i32
类型的值。然后再用fn
定义了一个函数类型,这个函数类型有type
关键字定义了它的别名IncType
。在main
函数中定义了一个变量func
,其类型就为IncType
,并赋值为inc
,然后在pirntln
宏中调用:func(3)
。可以看到,inc
函数的类型其实就是IncType
。这里有一个问题,我们将inc
赋值给了func
,而不是&inc
,这样是将inc
函数的拥有权转给了func
吗,赋值后还可以以inc()
形式调用inc
函数吗?先来看一个例子:
fn main() {
let func: IncType = inc;
println!("3 + 1 = {}", func(3));
println!("3 + 1 = {}", inc(3));
}
type IncType = fn(i32) -> i32;
fn inc(n: i32) -> i32 {
n + 1
}
这说明,赋值时,inc
函数的所有权并没有被转移到 func
变量上,而是更像不可变引用。在&
*
函数作为参数
函数作为参数,其声明与普通参数一样。看下例:
fn main() {
println!("3 + 1 = {}", process(3, inc));
println!("3 - 1 = {}", process(3, dec));
}
fn inc(n: i32) -> i32 {
n + 1
}
fn dec(n: i32) -> i32 {
n - 1
}
fn process(n: i32, func: fn(i32) -> i32) -> i32 {
func(n)
}
例子中,process
就是一个高阶函数,它有两个参数,一个类型为i32
的n
,另一个类型为fn(i32)->i32
的函数func
,返回一个i32
类型的参数;它在函数体内以n
作为参数调用func
函数,返回func
函数的返回值。运行可以得到以下结果:
3 + 1 = 4
3 - 1 = 2
不过,这不是函数作为参数的唯一声明方法,使用泛型函数配合特质(trait
)也是可以的,因为trait
FnOnce
、Fn
或FnMut
。将上例中的process
函数定义换成以下形式是等价的:
fn process<F>(n: i32, func: F) -> i32
where F: Fn(i32) -> i32 {
func(n)
}
允许把闭包作为参数来生成新的函数:
fn add_one(x: i32) -> i32 { x + 1 }
fn apply<F>(f: F, y: i32) -> i32
where F: Fn(i32) -> i32
{
f(y) * y
}
fn factory(x: i32) -> Box<Fn(i32) -> i32> {
Box::new(move |y| x + y)
}
fn main() {
let transform: fn(i32) -> i32 = add_one;
let f0 = add_one(2i32) * 2;
let f1 = apply(add_one, 2);
let f2 = apply(transform, 2);
println!("{}, {}, {}", f0, f1, f2);
let closure = |x: i32| x + 1;
let c0 = closure(2i32) * 2;
let c1 = apply(closure, 2);
let c2 = apply(|x| x + 1, 2);
println!("{}, {}, {}", c0, c1, c2);
let box_fn = factory(1i32);
let b0 = box_fn(2i32) * 2;
let b1 = (*box_fn)(2i32) * 2;
let b2 = (&box_fn)(2i32) * 2;
println!("{}, {}, {}", b0, b1, b2);
let add_num = &(*box_fn);
let translate: &Fn(i32) -> i32 = add_num;
let z0 = add_num(2i32) * 2;
let z1 = apply(add_num, 2);
let z2 = apply(translate, 2);
println!("{}, {}, {}", z0, z1, z2);
}
函数作为返回值
函数作为返回值,其声明与普通函数的返回值类型声明一样。看例子:
fn main() {
let a = [1,2,3,4,5,6,7];
let mut b = Vec::<i32>::new();
for i in &a {
b.push(get_func(*i)(*i));
}
println!("{:?}", b);
}
fn get_func(n: i32) -> fn(i32) -> i32 {
fn inc(n: i32) -> i32 {
n + 1
}
fn dec(n: i32) -> i32 {
n - 1
}
if n % 2 == 0 {
inc
} else {
dec
}
}
例子中的高阶函数为get_func
,它接收一个fn(i32) -> i32
的函数,若传入的参数为偶数,返回inc
,否则返回dec
。这里需要注意的是,inc
函数和dec
函数都定义在get_func
内。在函数内定义函数在很多其他语言中是不支持的,不过
fn main() {
let f = get_func();
println!("{}", f(3));
}
fn get_func() -> fn(i32)->i32 {
let a = 1;
fn inc(n:i32) -> i32 {
n + a
}
inc
}
// 会抛出异常