Well, it's kind of the other way around. Any datastructure that offers any kind of getter will have an signature for such getters of the form:
fn get<'duration> (
datastructure: &'duration DataStructure,
) -> &'duration Field
fn get_mut<'duration> (
datastructure: &'duration mut DataStructure,
) -> &'duration mut Field
This is, for instance, the case for IndexMut
(and say, Vec<T>
):
impl<T> IndexMut<usize> for Vec<T> {
fn index_mut<'duration> (
self: &'duration mut Vec<T>,
idx: usize,
) -> &'duration mut T
In all these cases, the 'duration
within which the borrow to the Field
or to the indexed element lasts is "connected to" / "equal to" the 'duration
within which the whole datastructure is borrowed.
And it turns out there is not really a way to, directly, express the disjointness of fields when using getters.
-
So, tuples and struct
(ure)s are kind of the exception here. When you &
or &mut
borrow one .field
or .tuple_idx
, it involves special magical borrowing rules so that Rust knows the other fields aren't borrowed.
That is, it is impossible in Rust to define a .x_mut()
method / getter so that thing.x_mut()
is fully equivalent to &mut thing.x
.
The only option / workaround then is to use a "get
-them-all(-at-once)" getter, also called a "projection method", which yields a new datastructures containing all the desired simultaneous and non-overlapping borrows at once. Such new data structure can also be called a view type.
Example
Consider:
struct Foo { x: i32, y: i32 }
impl Foo {
fn x_mut (self: &'_ mut Foo)
-> &'_ mut i32
{
&mut self.x
}
fn y_mut (self: &'_ mut Foo)
-> &'_ mut i32
{
&mut self.y
}
}
let mut foo = Foo { x: 0, y: 0 };
Then, the following works:
let x = &mut foo.x;
let y = &mut foo.y;
::core::mem::swap(x, y); // OK
but the following does not:
let x = foo.x_mut();
let y = foo.y_mut(); // Error, the previous `&mut` borrow on `foo`
// must still be active / held so that the
// `x` borrow itself remains usable
// (as stated by the signature of `fn x_mut()`),
// and `x` must remain usable since it is used
// in the following line:
::core::mem::swap(x, y);
And the workaround:
impl Foo {
fn x_and_y_mut (self: &'_ mut Foo)
-> (&'_ mut i32, &'_ mut i32)
{
(&mut self.x, &mut self.y)
}
}
let (x, y) = foo.x_and_y_mut();
::core::mem::swap(x, y);
- Here, my "view type" is a simple
(&mut i32, &mut i32)
tuple, but since tuples can become less readable as the number of fields increases, defining our own wrapper around it can be a more robust approach:
#[non_exhaustive]
pub
struct MutBorrowedFieldsOfFoo<'duration> {
pub
x: &'duration mut i32,
pub
y: &'duration mut i32,
}
impl Foo {
pub
fn fields_mut<'duration> (
self: &'duration mut Foo,
) -> MutBorrowedFieldsOfFoo<'duration>
{
let Self { x, y } = self; // abuse the magic of match ergonomics
MutBorrowedFieldsOfFoo { x, y }
}
}
let fields = foo.fields_mut();
::core::mem::swap(fields.x, fields.y);
Obviously when the x
and y
fields of Foo
are already public to begin with, there is no point in doing all this; but when privacy is involved, it can become useful:
mod lib {
#[derive(Default)]
pub
struct Foo {
/* private */
immutable_x: i32,
pub
y: i32,
}
impl Foo {
fn x (self: &'_ Foo)
-> &'_ i32
{
&self.immutable_x
}
}
}
use lib::Foo;
fn main ()
{
let mut foo = Foo::default();
// let x = &foo.x; /* Error, field `x` is private */
let x = foo.x();
let y = &mut foo.y; // Error, `foo` is `&`-borrowed until `x` is no longer used.
*y = *x;
}
hence the workaround:
#[non_exhaustive]
pub
struct FieldsOfFoo<'duration> {
pub
x: &'duration i32,
pub
y: &'duration mut i32,
}
impl Foo {
pub
fn fields<'duration> (
self: &'duration mut Foo,
) -> FieldsOfFoo<'duration>
{
let Self { immutable_x: x, y } = self;
FieldsOfFoo { x, y }
}
}
with it:
let mut foo = Foo::default();
let FieldsOfFoo { x, y, .. } = foo.fields();
*y = *x; // OK