Rust 闭包

2 minute read Published: 2021-11-20

本文代码

fn call<F>(f: F)
where
    F: Fn(),
{
    f();
}

fn call_mut<F>(mut f: F)
where
    F: FnMut(),
{
    f();
}

fn call_once<F>(f: F)
where
    F: FnOnce(),
{
    f();
}

#[derive(Debug)]
struct V(i32);

#[test]
fn test_fn() {
    let v = 0;

    let f = || {
        // `v` 通过引用操作,闭包为 `Fn`
        println!("{}", v);
    };

    // 可调用多次
    call(f);
    call(f);
}

#[test]
fn test_fn_mut() {
    let mut v = 0;

    let mut f = || {
        // `v` 通过可变引用操作,闭包为 `FnMut`,所有权移动至闭包内
        v += 1;
        println!("{}", v);
    };

    // 可调用多次
    call_mut(&mut f);
    call_mut(&mut f);
}

#[test]
fn test_fn_once() {
    let v = V(0);

    // `v` 未实现 `Copy` trait 时:
    //   `v` 所有权移动至闭包内,此闭包只可调用一次。
    //
    // `v` 实现 `Copy` trait 时:
    //   将 `v` 复制一份至闭包内,此闭包可调用多次。
    let f = || {
        // `v` 通过值操作,闭包为 `FnOnce`,所有权移动至闭包内
        drop(v);
    };

    call_once(f);
}

#[test]
fn test_move() {
    let v = V(0);

    // move:
    //   `v` 未实现 `Copy` trait 时:
    //     强行将变量所有权移至闭包内,闭包类型不会发生改变,但此闭包只可调用一次。
    //
    //   `v` 实现 `Copy` trait 时:
    //     将变量复制一份至闭包内,此闭包可调用多次。
    let f = move || {
        println!("{:?}", v);
    };

    // call(f);
    // call_mut(f);
    call_once(f);
}