rust基础相关:move关键字如果是转移所有权,为什么这段代码是可以编译通过的?
kingsama2025/03/29 19:35:08提问2025/03/29 19:35:08更新
    rust基础move所有权线程
220

我是一个刚学rust的菜鸟,各位佬勿嫌弃,我已经尽力自己去解决了。

use std::thread;
/// 使用的是rustc 1.85.1 (4eb161250 2025-03-15) 版本
/// 最后代码可以编译通过,并打印7,但是这就很奇怪了?
fn main1() {
    let mut x = 6;
    let j = thread::spawn(move || {  //按照我的理解,move发生了所有权转移,此时x应该由main线程转移到了这里。
        x = x * 2;
        thread::spawn(move || {  //move发生所有权转移,此时x由外一层的线程转移到这里一层的线程
            x = x * 2;
        })
    });
    x = x + 1;   //为什么这里main线程还可以继续访问x的值
    j.join().unwrap().join().unwrap();  //main线程阻塞等待结果,x转移到内部线程之后,并没有说明内部线程有将x的所有权移交还给main线程
    println!("{}", x);  //main线程 结果这里还是能打印x的值。
}
// 我的一些思考:
// 我不太清楚rust是否会存在指令重排的问题,不过java是有的,从这点出发考虑,
// 编译器让main线程先进行+1打印后再移交所有权给子线程。不过这里main线程有进行等待子线程,
// 如果发生指令重排,我觉得编译器应该不会将println提前到j.join()之前,因为这会破坏语义。

// 寻求大语言模型的帮助:
// 令我感到沮丧的是,gpt等一众模型对这段代码的判断都是无法编译通过,这是和事实相矛盾的,
// 在我向模型纠正这一点后,语言模型指出是因为x的是类型i32;其实现了copy trait。
// 因此move行为实际上是进行了copy而非所有权转移。于是我设计一个可能不是很完美的实验。
// 其实验的目标是:观察未实现copy trait的结构,在move中的行为是所有权转移还是copy

#[derive(Debug)]
// 一个自定义struct,它没有实现copy trait
struct MyStruct {
    val: i32,
    msg: String,
}

fn main(){
    let mut x = MyStruct{val: 6, msg: "main线程中的值:".to_string()};
    let j = thread::spawn(move || {
        x.val=x.val*2;
        x.msg="外线程中的值:".to_string();
        println!("{}{}", x.msg,x.val);
        thread::spawn(move || {
            x.val=x.val*2;
            x.msg="里线程中的值:".to_string();
            println!("{}{}", x.msg,x.val);
        })
    });
    x.val=x.val*2;
    x.msg="main线程中修改后的值:".to_string();  //  todo
    j.join().unwrap().join().unwrap();
    println!("{}{}", x.msg,x.val);
    println!("{:?}", x);
}

// 以上这段代码依旧可以编译通过,我觉得可以说明gpt的解释是有误差的。
// 因此我依旧没能理解为什么可以编译通过,而且更令我感到困惑的:删除todo处
// 这一行代码,编译竟然不通过?因为rust语言给我的刻板影响是:如果你做了越多的事,
// 被编译器驳回的概率就越大,而此时todo处,删除后,它报错了?有点颠覆我的认知。


还有一点疑问:有了解到rust的线程模型与操作系统线程是1:1的关系。这点和java的线程模型一致,或者说,java的线程是托付给操作系统执行的。不过java的线程启动时机是需要start(),而在rust中似乎spawn就已经创建并启动了。这里就比较疑惑了:

1:一个线程创建和启动是一起的(因为只有一条语句),如果是条件依赖线程,rust该如何描述这种关系(我想表达的类似于实现java中CompletableFuture 或者js中的异步编程效果)

2:rust启动的线程也是托付给操作系统完成的吗?如果是rust自己管理的,那线程的生命周期会在什么时候消亡。如果是操作系统管理的,rust能够确保资源不泄露吗,或者说rust彻底丧失了对线程管理的控制权吗?


回答(4
    推荐问答
      Simple Empty
      暂无数据