← 返回首页

FIELD NOTE / 2026-08-15

rust语法

rustlings智能指针之arc1.rs

这个练习的目标是:让 8 个线程共享同一个 `Vec<u32>`。由于线程可能并发执行,不能使用普通的 `Rc`,而要使用线程安全的引用计数智能指针 `Arc`。

这个练习的目标是:让 8 个线程共享同一个 Vec<u32>。由于线程可能并发执行,不能使用普通的 Rc,而要使用线程安全的引用计数智能指针 Arc

需要补充两处:

let shared_numbers = Arc::new(numbers);

以及循环中:

let child_numbers = Arc::clone(&shared_numbers);

完整代码如下:

#![forbid(unused_imports)]
use std::{sync::Arc, thread};

fn main() {
    let numbers: Vec<_> = (0..100u32).collect();

    let shared_numbers = Arc::new(numbers);

    let mut join_handles = Vec::new();

    for offset in 0..8 {
        let child_numbers = Arc::clone(&shared_numbers);

        let handle = thread::spawn(move || {
            let sum: u32 = child_numbers
                .iter()
                .filter(|&&n| n % 8 == offset)
                .sum();

            println!("Sum of offset {offset} is {sum}");
        });

        join_handles.push(handle);
    }

    for handle in join_handles.into_iter() {
        handle.join().unwrap();
    }
}

关键点

1. Arc::new(numbers)

let shared_numbers = Arc::new(numbers);

Vec<u32> 放进 Arc 中。此时 shared_numbers 的类型大致是:

Arc<Vec<u32>>

Arc 是原子引用计数指针,允许多个线程共同拥有同一份数据。

2. Arc::clone

let child_numbers = Arc::clone(&shared_numbers);

这不会复制整个 Vec,只会增加 Arc 的引用计数,并创建一个新的共享指针。

每个线程获得一个自己的 Arc

shared_numbers
      │
      ├── child_numbers for thread 0
      ├── child_numbers for thread 1
      ├── child_numbers for thread 2
      └── ...

3. move

thread::spawn(move || {
    // 使用 child_numbers
});

move 会把 child_numbers 的所有权移动进线程闭包中。这样线程可以安全地独立持有这个 Arc

4. 过滤条件

.filter(|&&n| n % 8 == offset)

例如:

  • offset == 0:选择 0, 8, 16, ...
  • offset == 1:选择 1, 9, 17, ...
  • offset == 7:选择 7, 15, 23, ...

filter 中的 &&n 是因为:

  • iter() 产生 &u32
  • filter 的闭包参数又会接收一个引用,即 &&u32
  • 两次解引用后得到实际的 u32

最终 8 个线程的和应该分别类似于:

Sum of offset 0 is 600
Sum of offset 1 is 612
Sum of offset 2 is 624
...
Sum of offset 7 is 684

线程执行顺序不确定,所以输出顺序可能不同。