Reputation: 559
I have some Rust code that I find to be pretty smelly. I want to get mutable references from the fields of a struct at the same time, but of course Rust does not allow more than one mutable reference at the same time.
What I have been doing currently is basically making a newtype of a tuple and then pattern matching the two different types out into separate ref mut
patterns. Not a huge fan of the way this looks in practice.
struct Foo;
impl Foo {
fn foo(&mut self, bar: &mut Bar) {
bar.bar();
}
}
struct Bar;
impl Bar {
fn bar(&mut self) {
println!("bar")
}
}
struct FooBar((Foo, Bar));
impl FooBar {
fn foobar(&mut self) {
let &mut FooBar((ref mut foo, ref mut bar)) = self;
foo.foo(bar);
println!("foobar");
}
}
fn main() {
let mut foobar = FooBar((Foo, Bar));
foobar.foobar();
}
Is there a better way I should be doing this? Or perhaps some ideas about general ways to structure the code so that I do not need this newtype?
Upvotes: 3
Views: 737
Reputation: 299800
Rust's borrow analysis natively supports borrowing disjoint fields.
You can use either a tuple-like struct
or a regular struct
, and it all just works:
struct Foo;
impl Foo {
fn foo(&mut self, bar: &mut Bar) {
bar.bar();
}
}
struct Bar;
impl Bar {
fn bar(&mut self) {
println!("bar")
}
}
struct Tupled(Foo, Bar);
impl Tupled {
fn foobar(&mut self) {
self.0.foo(&mut self.1);
}
}
struct Named {
foo: Foo,
bar: Bar,
}
impl Named {
fn foobar(&mut self) {
self.foo.foo(&mut self.bar);
}
}
fn main() {
let mut tupled = Tupled(Foo, Bar);
tupled.foobar();
let mut named = Named{ foo: Foo, bar: Bar };
named.foobar();
}
This compiles and runs in the playground.
Upvotes: 3
Reputation: 31173
You don't need to newtype a tuple, you can just create a tuple-struct directly:
struct FooBar(Foo, Bar);
Then you can write your code pretty concisely as
fn foobar(&mut self) {
self.0.foo(&mut self.1);
println!("foobar");
}
by using tuple indexing instead of a let binding.
Upvotes: 4