enum Bar {
Baz(String),
Ham,
}
struct Foo {
bar: Bar,
}
pub fn main() {
let foo = Foo { bar: Bar::Baz(String::from("abc")) };
for _ in 0..3 {
match foo.bar {
// Compiler complains that value was moved here.
// This match, therefore, is unlikely to trigger again
// in next iteration(s).
Bar::Baz(s) => {
match s.as_str() {
"abc" => (),
_ => ()
}
},
_ => ()
}
}
}
The compiler complains:
error[E0382]: use of moved value
--> src/main.rs:15:22
|
15 | Bar::Baz(s) => {
| ^ value moved here, in previous iteration of loop
|
= note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
As noted in the comment within code:
Compiler complains that value was moved here. This match, therefore, is unlikely to trigger again in next iteration(s).
Seems like my inference is incorrect and I am not clear about what's happening here. Would appreciate an explanation.
Because you match on the enum, the content is moved out. If you match on the same value over, and over again it will keep trying to move something that is already gone. If you add ref in front of s, so it is Bar::Baz(ref s) then it will only reference and not move the inner value. It compiles fine then. (see playground for version with ref)
Normally in a loop I would think you would match on a different value (maybe from an array or iterator?) each time and this would work. In this case, you are always matching the same value, so why not move it outside the loop, just do it once, and then the compiler won't complain that you keep trying to move it?
I mean the issue is that by using foo.bar, you are taking ownership of foo which destroys the foo value. Since this destroys it, it is not accessible in the next iteration, which you can fix by borrowing it instead by matching on &foo.bar (or by adding ref to the matched case).
No, foo cannot exist without a value in the bar field. You can swap out the value with another one using mem::replace, or you can just borrow the field.
I assume you don't want to take ownership forever, otherwise what's the point of the Foo struct? If you want to mutate bar, you can just take a mutable reference with let bar = &mut foo.bar;.