一句话:fn 是类型,Fn 是 Trait。不过对于小白,这句话好像什么都没说。
用法
fn 是类型,啊对,就是和 i32,f64 同一类的东西,那么用法就和他们一样咯,放在变量的后面表示变量的类型。例如以下代码中,f 是函数,接受一个 i32 类型的参数,返回 ()。
rust
fn foo1(f: fn(i32) -> (), x: i32) {
    f(x)
}
1
2
3
2
3
Fn 是 Trait,说人话大概是可以被多次调用的函数。类似的,还有 FnMut 和 FnOnce,实现了 Fn 的类型必定实现了 FnMut 和 FnOnce。任何一个函数都实现了 Fn。
注意,这里说的是函数,闭包的情况比较复杂,后面再说。
既然是 Trait,用法就是约束泛型参数。例如下面的代码中,f 的类型是 T,是实现了 Fn (i32) -> () 的函数。
rust
fn foo2<T: Fn(i32) -> ()>(f: T, x: i32) {
    f(x)
}
// 泛型约束也可以写到后面
fn foo3<T>(f: T, x: i32) -> () where T: Fn(i32) -> () {
    f(x)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
区别和联系
先看下面这段程序,后面慢慢解释。
rust
fn main() {
    fn fun1(x: i32) -> () {
        println!("fun1({x})");
    }
    let fun2 = |x| {
        println!("fun2({x})");
    };
    foo1(fun1, 1);
    foo2(fun1, 2);
    foo1(fun2, 3);
    foo2(fun2, 4);
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
fun1的类型是fn (i32) -> (),完美符合,没问题- 任何一个函数都实现了 
Fn,满足泛型约束,没问题 - 没有捕获变量的闭包可以被转换成对应的函数,于是没问题
 - 编译器为这个闭包实现了 
Fn,于是也没问题 
前两个应该是没有疑问的,后两个就比较有意思了。注意这个例子中闭包是没有捕获变量的,如果有会怎样呢。

哈哈,炸了。编译器提示我们:closures can only be coerced to fn types if they do not capture any variables. 捕获变量的闭包是不能转换成 fn 类型的。
而第 4 次调用没有报错!说明这个闭包也实现了 Fn。那么到底是怎么回事呢,引用 Nichts Hsu 的总结:
任何一个函数都实现了 FnOnce, FnMut, Fn, Copy。
对于闭包:
- 必定实现 
FnOnce。 - 如果闭包能仅通过可变引用访问上下文变量,则实现 
FnOnce和FnMut。 - 如果闭包能仅通过不可变引用访问上下文变量,或者不访问上下文变量,则实现 
FnOnce,FnMut,Fn,Copy。 move会导致闭包所捕获变量被移动到闭包的匿名结构体内,但是不会影响该闭包实现哪些FnTraits。- 当闭包实现 
Fn时,move关键字会导致闭包不总是实现Copy,而是根据捕捉的变量是否实现Copy来决定自身是否实现Copy。 
当调用一个函数或闭包时,编译器首先寻找 call 方法(对应 Fn)来调用,如果没有,则寻找 call_mut 方法(对应 FnMut),再没有再寻找 call_once 方法(对应 FnOnce)。
参考:Rust 中函数与闭包与 Fn Traits 探讨,作者 Nichts Hsu