Has anyone ever had any success splitting the mutability to only one field of a struct like this? Playground
Yes, this is the hard problem. Common pattern is to split the struct into two, the shared half and the mutable half each stored in their own variable.
In these situations it is useful to be strict about the terminology and the semantics: you want to have a struct for which you want to restrict exclusive access (&mut
) to some of its fields. This is just another form of API limitation, and is thus generally achieved through privacy and modules:
pub use privacy_boundary::Struct;
mod privacy_boundary {
pub
struct Struct {
pub
mutable_field: A,
immutable_field: B,
}
impl Struct {
pub
fn new (…) -> Self
{ … }
pub
fn immutable_field (self: &'_ Struct) -> &'_ B
{
&self.immutable_field
}
}
}
so that
let mut s = Struct::new(…);
s.mutable_field = …; // OK
s.immutable_field = …; // Error, private field
dbg!(&s.immutable_field()); // OK
The main drawback here are ergonomics, but for that you can go and use handy proc-macros, such as:
Finally, going back to the start of my post, there could be a different problem when talking about "separating mutability within a struct": instead of talking about pub
licly forwarding (or not) the exclusive access (&mut
), we can talk about a struct we know is gonna be shared (&
access only), and at that point will only be mutable the fields that feature Shared Mutability / Interior Mutability, such as:
use ::core::cell::Cell as Mut; // Single-threaded mutation
struct Shared {
mutable_field: Mut<i32>,
immutable_when_shared: i32,
}
so that, if you have, say, an s: Rc<Shared>
or a s: &Shared
, you can do:
s.mutable_field.set(0);