You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2021年12月博客中的Rust代码为何宣称可编译,实际运行报错?

Rust线程安全计数器编译问题的拆解

为啥你会遇到闭包要move的错误

Rust里用std::thread::spawn创建线程时,线程闭包必须满足'static生命周期约束——说白了就是线程的执行时长不受当前代码块控制,Rust得确保闭包里捕获的内容不会提前失效。如果你的闭包只抓了计数器的&self引用,没把所有权转移给闭包,编译器肯定会报错要求添加move关键字,否则无法保证线程运行时这个引用还处于有效状态。

博客里的代码能编译的两种可能情况

1. 作者展示代码时遗漏了move关键字

正常实现线程安全计数器,肯定要靠Arc<Mutex<Counter>>来实现跨线程的所有权共享,正确写法里闭包必须加move,示例代码如下:

use std::sync::{Arc, Mutex};
use std::thread;

struct Counter {
    count: u32,
}

impl Counter {
    fn increment(&self) {
        let mut count = self.count.lock().unwrap();
        *count += 1;
    }
}

fn main() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter_clone = Arc::clone(&counter);
        // 此处必须加move,将counter_clone的所有权转移给线程闭包
        let handle = thread::spawn(move || {
            counter_clone.increment();
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Count: {}", counter.lock().unwrap().count);
}

如果博客里展示的代码没写move,要么是作者笔误遗漏,要么是你查看时没注意到关键细节。

2. 作者使用了Nightly版本的作用域线程

2021年12月时,Rust稳定版还未支持作用域线程(稳定版到2022年8月的1.63版本才正式引入std::thread::scope),但Nightly版本已经可以使用这个不稳定特性。作用域线程能保证线程在指定代码块执行完毕前终止,所以闭包可以直接捕获非'static的引用,不需要move关键字,示例代码如下:

#![feature(scoped_threads)]
use std::sync::Mutex;
use std::thread;

struct Counter {
    count: Mutex<u32>,
}

impl Counter {
    fn increment(&self) {
        let mut count = self.count.lock().unwrap();
        *count += 1;
    }
}

fn main() {
    let counter = Counter { count: Mutex::new(0) };

    thread::scope(|s| {
        for _ in 0..10 {
            // 此处无需move,作用域保证线程在scope结束前完成执行
            s.spawn(|| {
                counter.increment();
            });
        }
    });

    println!("Count: {}", counter.count.lock().unwrap());
}

这段代码在2021年的Nightly版本中可以正常编译运行,但依赖不稳定特性,并非稳定版的常规用法。

总结

2021年12月的Rust稳定版中,使用普通thread::spawn的情况下,把increment方法参数从&mut self改为&self的代码必须配合move闭包(或Arc克隆)才能编译。博客里的代码能正常运行,要么是作者使用了Nightly版的作用域线程,要么是展示代码时遗漏了move关键字。

内容的提问来源于stack exchange,提问作者Zebrafish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:13:11