I assume the Foo struct has been shallow copied so I can overwrite the contents in the stack without a segfault, but I thought the ownership had moved and that rustc would stop me from doing this.
This seems nonsensical to me. There’s no utility to being able to assign a field of a moved value, and it certainly doesn’t do what a casual reader would think it does.
In general moves are tracked at a pretty narrow level of granularity. We intend to eventually permit you to “fill” both fields back in and then use the structure again. I guess that doesn’t work today. I have to go look again at the moves code, but I think in general one of the things I’d like to pursue post 1.0 is extending the type system to deal better with things that have been moved from (in particular I want to support moves out of &mut pointers, so long as you restore the value before doing anything fallible). Anyway I think this example more-or-less falls out of treating things in a general way, though you could imagine rules that say “if you move f, you can never again touch any subfields of f without restoring f as a unit”.
> In general moves are tracked at a pretty narrow level of granularity.
That makes sense, and it would make closures a lot nicer (rather than individually borrowing members of a struct), but I notice it doesn’t seem to work that way right now:
#[deriving(Show)]
struct Bar;
struct Foo {
pub foo: Bar,
pub bar: Bar,
}
fn main() {
let mut x = Foo { foo: Bar, bar: Bar };
let c = || {
x.foo = Bar;
};
println!("{}", x.bar); // error: cannot borrow x.bar as immutable because x is also borrowed as mutable
}
> you could imagine rules that say “if you move f, you can never again touch any subfields of f w
ithout restoring f as a unit”.
I like this as a nice middle ground. Restoring the individual fields of f seems error prone and difficult to read - I’d be very inclined to have the definition of the struct open in another tab, just to make sure all the fields really are being restored. Restoring as a unit makes sure it all happens in one sane place, and helps assure the reader that all the fields really are restored at that point.
That is correct, closures always borrow (or move) the variables they
touch. This may change in the future. This is separate from the
tracking within a single fn body, however, which is done at a finer
level of granularity.
Actually, that surprises me. I’ll have to look again, but I thought we
always modeled closure captures at the variable level at the moment,
not subpaths.