I made this minimal example which outlines my problem:
// Foo is from an external crate, I have no control over it.
struct Foo {
}
impl Foo {
fn foo(self) -> Self {
self
}
}
// Bar is part of my project.
struct Bar {
f: Foo
}
impl Bar {
fn bar(&mut self) {
self.f = self.f.foo();
}
}
fn main() {
let mut b = Bar { f: Foo { } };
b.bar();
}
So I'm trying to change f: Foo from b: Bar using the function Foo::foo. To me this seems reasonable. I have a mutable borrow of self. I can't consume self but I can do whatever I want with the insides of self.
It gives me this error:
error[E0507]: cannot move out of borrowed content
--> main.rs:17:18
|
17 | self.f = self.f.foo();
| ^^^^ cannot move out of borrowed content
My questions are:
Why does the error message claim that self cannot be moved? I want to move f, not self.
Is this even possible? I fiddled with it for some time but couldn't get it to work.
If it is possible, how? If it's not then why? What is the key point that I'm missing here?
The best way to get around that is to have bar take self, and then return self after reassigning self.foo.
// Foo is from an external crate, I have no control over it.
struct Foo {
}
impl Foo {
fn foo(self) -> Self {
self
}
}
// Bar is part of my project.
struct Bar {
f: Foo
}
impl Bar {
fn bar(mut self) -> Self {
self.f = self.f.foo();
self
}
}
fn main() {
let mut b = Bar { f: Foo { } };
let b = b.bar();
}
f is part of self since Bar owns it; f needs to move because its foo() wants it by value. Since you only have a mutable borrow (i.e. &mut self) of Bar, you cannot move out of it.
What you can do here is store f in an Option:
struct Bar {
f: Option<Foo>
}
impl Bar {
fn bar(&mut self) {
let f = self.f.take().unwrap();
self.f = Some(f.foo());
}
}
You can always use mem::uninitialized() if Foo isn't trivial to construct, seeing whatever you're putting there doesn't ever get used... This could come back to bite you if Foo::foo() panics though, seeing as now your Bar is in an inconsistent state (see Pre-Pooping Your Pants With Rust for ways you can deal with this).