Reference and Mutable Reference of methods on disjoint fields

Hi Rustaceans!

Is there some pattern that allows mutable and shared references on the same object at the same time, when those references are held on disjoint fields within the containing type?

I'm aware of interior mutability types like Cell and RefCell, however I was hoping there would be a lifetime related solution considering they are disjoint, as neither of those interior mutability allow a direct shared reference (i.e. &T) to be taken.

(See playground).

struct First<T> { value: T }
struct Second<T> { value: T }

struct Foo<T> {
    first: First<T>,
    second: Second<T>,
}

impl<T> First<T> {
    fn get_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
impl<T> Second<T> {
    fn get(&self) -> &T {
        &self.value
    }
}
impl<T> Foo<T> {
    fn get_first_mut(&mut self) -> &mut T {
        self.first.get_mut()
    }
    fn get_second(&self) -> &T {
        self.second.get()
    }
}

fn main() {
    let mut x = Foo {
        first: First { value: 123 },
        second: Second { value: 123 },
    };
    // This is fine:
    {
        let a = x.first.get_mut();
        let b = x.second.get();
        println!("{} {}", a, b);
    }
    // This has first borrowed mutable when second is attempted.
    {
        let a = x.get_first_mut();
        let b = x.get_second();
        println!("{} {}", a, b);
    }
}

Yes there is – if you know the methods will use disjoint fields, don't take the entirety of self. Just pass to the methods whatever fields they need to operate on (and drop the getters – they are not idiomatic anyway).

See also this article for other approaches, e.g. view structs.

2 Likes

Thanks, that looks exactly like what I was looking for!

To clarify for @H2CO3: the example was just meant to be minimal illustrative code for the type of references I wanted to take, in a real situation it would be a lot more complicated than getters. The interior types should remain an implementation detail if possible.

It’d be nice to have something like lifetimes for the field subsets discussed in the blog post.

Something like:

struct Foo<"a, "b> {
    first: First<"a, "b>,
    second: Second<"b>,
}
impl<"a,"b> Foo<"a, "b> {
    fn do_something(&"a mut self) -> &X {…}
    fn get_that(&"b self, I: Idx) -> &Y {…}
}

I think the quote notation is perhaps too similar to lifetimes and could be confusing. However I like that the general syntax allows you to have higher granularity than the fields of the current type, which is something that none of the blog post solutions were great at.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.