Please enable Javascript to view the contents

[Rust 基础知识]闭包

 ·  ☕ 1 分钟

前言

    本文主要覆盖闭包的基础知识点。

基本语法

1
let add = |a:i32, b:i32| ->i32 { return a + b; };

闭包的返回值和参数类型是可以省略的:

1
let add = |a, b| { return a + b; };

和普通函数一样,最后的 return 也可以省略:

1
let add = |a, b| { a + b };

如果只有一条语句大括号也可以省略:

1
let add = |a, b| a + b;

变量捕获

Rust 中默认变量捕捉是根据使用自动选择捕捉形式。一般可以理解为 3 种:&T,&mut T。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct T(i32);

fn by_value(_: T) {}

fn by_mut(_: &mut T) {}

fn by_ref(_: &T) {}

fn main() {
    let x = T(1);
    let y = T(2);
    let mut z = T(3);

    let closure = || {
        by_value(x);
        by_ref(&y);
        by_mut(&mut z);
    };

    closure();
}

有时闭包的生命周期会超过原本的函数范围:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn return_closure_error()->impl Fn()->i32 {
    let a = 1;
    || a // error
}

fn return_closure()->impl Fn()->i32 {
    let a = 1;
    move || a 
}

对于这种情况我们可以使用 move 关键字全部通过 by value 方式捕捉。

不过细究之下还会有个小问题:

1
2
3
4
5
6
7

fn main() {
    let c = 3;
    let add = |a| move |b| a + b + c;

    println!("{}", add(1)(2));
}

我们不想通过 by value 的形式捕捉 c 怎么办呢?其实只要用 by value 形式捕获 c 的引用就可以了:

1
2
3
4
5
6
7

fn main() {
    let c = &3;
    let add = |a| move |b| a + b + c;

    println!("{}", add(1)(2));
}

这种情况可能在上例中有点无病呻吟的意思,不过结合多线程的场景就能理解。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use std::sync::Arc;
use std::thread;

fn main() {
    let states: Vec<_> = (0..10i32).collect();
    let shared_states = Arc::new(states);

    for _ in 0..10 {
        let shared = shared_states.clone();
        thread::spawn(move || {
            let _ = &shared;
        });
    }
}

我们肯定不希望直接把状态的所有权直接转移进特定线程,所以可以变通一下搞一个线程安全的 Arc 引用数据,然后 clone 它把它传进去。

分享

saberuster
作者
saberuster
一个喜欢编程和折腾的追风少年