crhino
crhino

Reputation: 559

Is there a better way of getting mutable references to disjoint struct fields?

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();
}

Rust Playground

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

Answers (2)

Matthieu M.
Matthieu M.

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

oli_obk
oli_obk

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

Related Questions