闭包

闭包或 lambda 表达式具有无法命名的类型。不过,它们会 实现特殊的 FnFnMutFnOnce 特征:

fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {
    println!("Calling function on {input}");
    func(input)
}

fn main() {
    let add_3 = |x| x + 3;
    println!("add_3: {}", apply_with_log(add_3, 10));
    println!("add_3: {}", apply_with_log(add_3, 20));

    let mut v = Vec::new();
    let mut accumulate = |x: i32| {
        v.push(x);
        v.iter().sum::<i32>()
    };
    println!("accumulate: {}", apply_with_log(&mut accumulate, 4));
    println!("accumulate: {}", apply_with_log(&mut accumulate, 5));

    let multiply_sum = |x| x * v.into_iter().sum::<i32>();
    println!("multiply_sum: {}", apply_with_log(multiply_sum, 3));
}

Fn(例如 add_3)既不会耗用也不会修改捕获的值,或许 也不会捕获任何值。它可被并发调用多次。

FnMut(例如 accumulate)可能会改变捕获的值。您可以多次调用它, 但不能并发调用它。

如果您使用 FnOnce(例如 multiply_sum),或许只能调用它一次。它可能会耗用 所捕获的值。

FnMutFnOnce 的子类型。FnFnMutFnOnce 的子类型。也就是说,您可以在任何 需要调用 FnOnce 的地方使用 FnMut,还可在任何需要调用 FnMutFnOnce 的地方 使用 Fn

编译器也会推断 Copy(例如针对 add_3)和 Clone(例如 multiply_sum), 具体取决于闭包捕获的数据。

默认情况下,闭包会依据引用来捕获数据(如果可以的话)。move 关键字则可让闭包依据值 来捕获数据。

fn make_greeter(prefix: String) -> impl Fn(&str) {
    return move |name| println!("{} {}", prefix, name)
}

fn main() {
    let hi = make_greeter("Hi".to_string());
    hi("there");
}