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