I found a strange behavior of rustc. In the following codes, setting val.modify to true is allowed by rustc, but val have moved into vals. Though this modification has no effect. Can someone explain that why rustc doesn't complain about it?
#[derive(Debug)]
struct A {
modify: bool,
}
fn do_something(inputs: &[A]) {
println!("In do_something, inputs: {:?}", inputs);
}
fn main() {
let mut val = A { modify: false };
// val should moved here
let vals = vec![val];
do_something(&vals);
// But we still can modify it
// Maybe rustc should complain about this?
val.modify = true;
// If you want to read val again, rustc will complain about that
// if val.modify {
// }
// Though your modification won't work
do_something(&vals);
}
Output:
In do_something, inputs: [A { modify: false }]
In do_something, inputs: [A { modify: false }]
Looks like the compiler is willing to ignore that line because it can see that it does nothing? If you try to use val (i.e. do something like, println!("{:?}", val);) the compiler will complain that val is moved.
Just because you've moved the old value out doesn't preclude you from writing a new value into the same storage location.
Also, modifying val has no effect on vals, because that's not how the language works at all. Modifying a value in one place cannot have any effect on values in other places. You would need a pointer of some kind for that, but val isn't a pointer.
Edit: huh, I could have sworn the compiler let you overwrite fields to reconstruct a structure after it had been moved. I was wrong. You can still do this, but you have to replace the entire structure.
Here's the thing: a structure is just a collection of values. You can overwrite the storage of a moved value just fine. By extension, you should logically be able to overwrite the storage of a moved struct one field at a time.
Unless there's some compelling reason not to, I think it'd make more sense to allow this to work.
I tried to write in the location using write_volatile, at this point the compiler complains. I imagine that once the operation can be optimized away, for the compiler everything is fine.
Second note: clippy does not say anything as well.
#[derive(Debug)]
struct A(i32);
#[derive(Debug)]
struct B {
x: A,
y: A,
}
fn main() {
let mut val = B { x: A(1), y: A(2) };
println!("{:?}", val);
let x = val.x;
println!("{:?}", x);
val.x = A(3);
println!("{:?}", val);
}
Oh, I forgot the most interesting part, if you try to read your modified value, rustc will complain about it. But if you just write it without reading it, rustc will ignore it. So you are allowed to write to a value but you can't read it anymore.
fn main() {
let mut val = A { modify: false };
// val should moved here
let vals = vec![val];
do_something(&vals);
// But we still can modify it
val.modify = true;
// You will get an error:
if val.modify {
println!("val: {:?}", val);
}
// Though your modification won't work
do_something(&vals);
}