Field-type lifetime bound

Hi, I was wondering if it is possible to create a lifetime bound referring only to a single field of a struct?
example of what I mean:

struct Foo {
    shared: S,
    a: Vec<A>,
    b: Vec<B>,
}
impl Foo {
    fn get_a(&mut self) -> &<something> A {todo!()}
    fn get_b(&mut self) -> &<something> B {todo!()}
}

where get_a and get_b both require mutable access to shared, but the returned references are immutable & independent. is it possible to specify some lifetime bound on the returned lifetimes (and the self) to tell the compiler that that the function calls don't have overlapping borrowing?

I know that you can borrow different fields mutably simultaneously, so the concept of these lifetimes for a single field only do exist, but I don't know if it is possible to specify them for a function call

There is currently no way to specify that. Depending on your exact use-case, you might be able to get something working with interior mutability (e.g. Cell or RefCell).

What you're describing seems to be a mix of two features: partial borrows and downgradable borrows[1]

There are proposals that would add these features to the language, but I am not aware of any progress on them.

Most proposals for partial borrows I've seen fell into bikeshedding cycles around:

  • what syntax to use for partial borrows
  • how to handle partial borrows to private fields without semver hazards
  • how to specify the set of fields to borrow

Downgradable borrows should have fewer issues (it could be solved by introducing a second lifetime to unique references, but it would require explicit opt-in from existing APIs, because it would be unsound for certain interior mutability types).


  1. the ability to downgrade a unique (i.e. mutable) reference to a shared (i.e. immutable) reference, and have that "unlock" the unique borrow on the referent ↩ī¸Ž

4 Likes

Well, that is kinda disappointing, seems I have to move the logic to the types of the fields (in my actual case they aren't vecs).
Also, my actual usecase is only partial borrows, b/c the functions modify the a and b fields, so even the immutable refrences would be invalidated.
Thanks for the answer, at least now I know that what I was hoping to do (currently) isn't possible

1 Like

You can use view structs to emulate partial borrowing to some extent.

4 Likes

A very simple solution would be to define a method that returns a tuple:

impl Foo {
    fn get_a_and_b(&mut self) -> (&Vec<A>, &Vec<B>) {
        (self.a, self.b)
    }
}
1 Like