面试题答案
一键面试主要基础差异
- Fn trait:
Fn
trait 是 Rust 中用于标记可调用类型的 trait。它有Fn
、FnMut
和FnOnce
三个相关 trait。Fn
表示可以多次调用且不获取参数的可变所有权,适用于那些不需要修改环境也不需要获取参数所有权的可调用对象。- 实现
Fn
trait 的类型,其调用签名为&self
,意味着调用时不会转移self
的所有权,也不会修改self
。
- 闭包:
- 闭包是一种匿名函数,可以捕获其定义环境中的变量。闭包在 Rust 中非常灵活,它们会根据使用方式自动推断实现
Fn
、FnMut
或FnOnce
trait。 - 如果闭包不获取环境变量的所有权,也不修改它们,那么它会实现
Fn
trait。如果闭包需要修改环境变量,它会实现FnMut
trait。如果闭包获取环境变量的所有权,它会实现FnOnce
trait。
- 闭包是一种匿名函数,可以捕获其定义环境中的变量。闭包在 Rust 中非常灵活,它们会根据使用方式自动推断实现
代码示例
// 定义一个实现 Fn trait 的结构体
struct Adder(i32);
impl std::ops::Fn(i32) -> i32 for Adder {
fn call(&self, x: i32) -> i32 {
self.0 + x
}
}
fn main() {
// 使用实现 Fn trait 的结构体
let adder = Adder(5);
let result1 = adder(3);
println!("Result from Fn trait implementation: {}", result1);
// 定义一个闭包,自动推断实现 Fn trait
let add_numbers = |x: i32| x + 10;
let result2 = add_numbers(5);
println!("Result from closure: {}", result2);
// 展示闭包根据捕获变量方式实现不同 Fn 系列 trait
let mut counter = 0;
// 这个闭包需要修改 counter,所以实现 FnMut
let mut increment_counter = || counter += 1;
increment_counter();
println!("Counter after increment: {}", counter);
let message = String::from("Hello");
// 这个闭包获取 message 的所有权,所以实现 FnOnce
let consume_message = move || println!("Consumed message: {}", message);
consume_message();
// 这里不能再使用 message,因为所有权被闭包获取了
// println!("Message: {}", message); // 这行会编译错误
}
在上述代码中:
Adder
结构体手动实现了Fn
trait,展示了传统的Fn
trait 实现方式。add_numbers
闭包由于没有修改或获取环境变量所有权,自动推断实现了Fn
trait。increment_counter
闭包修改了环境变量counter
,所以实现了FnMut
trait。consume_message
闭包获取了message
的所有权,实现了FnOnce
trait。