I have a struct behind a mutable reference and I want to replace one of its fields. Please take a look at the following code:
struct Data {
huge_vector_that_should_not_be_cloned: Vec<u8>, // not the only large member that should not be cloned
many_more_fields: u32,
}
struct A {
data: Data,
some_more_fields: u32,
}
struct B {
data: Data,
some_more_fields: String,
}
enum AOrB {
A(A),
B(B),
}
impl AOrB {
fn a_to_b(&mut self) {
// Cannot use e.g. mem::take, since Data has no reasonable default implementation
match self {
AOrB::A(a) => {
let data = a.data; // do not destructure data, in reality it is the "base struct" containing the state of a whole application
*self = AOrB::B(B {
data,
some_more_fields: "".into(),
});
}
_ => panic!(),
}
}
}
fn main() {
let data = Data {
huge_vector_that_should_not_be_cloned: Vec::new(),
many_more_fields: 0,
};
let mut a_or_b = AOrB::A(A {
data,
some_more_fields: 0,
});
a_or_b.a_to_b();
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `a.data` which is behind a mutable reference
--> src/main.rs:25:28
|
25 | let data = a.data;
| ^^^^^^
| |
| move occurs because `a.data` has type `Data`, which does not implement the `Copy` trait
| help: consider borrowing here: `&a.data`
For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` due to previous error
In a_to_b
, I am first consuming a
, leaving self
in an undefined state. Then I am replacing self
with something that I have constructed from a
, bringing it back into a defined state.
Since self
is a mutable reference, noone should be able to observe self
while being undefined. However, the compiler does not allow me to do this.
Is there a way to work around this? I would like to avoid implementing Default
for A
, because in my code, it has no reasonable Default
implementation, so I would like to avoid mem::take
. Also, I cannot just use clone
, because the struct is too large. Moreover, I would like to treat Data
as an atom, as in the real code there is much more large stuff than just one large vector that should not be cloned.
Ideally, I would like to only change the implementation of a_to_b
for this to work. Otherwise, I could for example make the data
member of A
into an option to achieve what I want.