我是一个刚学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处,删除后,它报错了?有点颠覆我的认知。