How do I write a method that returns a reborrow of a `&mut` field without borrowing the struct?

I'm looking for help finding an idiomatic way to:

  • Create a temporary value which holds a mutable reference to something.
  • Use a method on that temporary value which returns a reborrow of that mutable reference.
  • Return the reborrow after dropping that temporary value.
struct Foobar<'a> {
    foo: &'a mut u32
}

impl<'a> Foobar<'a> {
    fn borrow(&mut self) -> &'a mut u32 {
        do_complex_stuff_with(self.foo);
        self.foo
    }
}

fn create_then_drop_foobar<'a>(ptr: &'a mut u32) -> &'a mut u32 {
    let foobar = Foobar { foo: ptr };
    foo.borrow()
}

This gives me the following error:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
 --> src/lib.rs:9:9
  |
6 | impl<'a> Foobar<'a> {
  |      -- lifetime `'a` defined here
7 |     fn borrow(&mut self) -> &'a mut u32 {
  |               - let's call the lifetime of this reference `'1`
8 |         //do_complex_stuff_with(self.foo);
9 |         self.foo
  |         ^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

Is there a way to express what I'm trying to do in a way the borrow checker understands?

Reborrow creates a new loan with a new lifetime.

You could return the original if you removed it from the struct and gave away your only copy.

Otherwise Rust must prevent this method from being called more than once at a time, and the source of the reborrow must stay borrowed.

If you could return a "copy" of a &mut reference without freezing its owner, it would allow calling the
method more than once and break exclusivity of &mut.

2 Likes

Since you are dropping FooBar, you might as well consume it as below. But to get better feedback you should post a more realistic example so we can understand the constraints you have. (Also please post something that compiles.)

fn do_complex_stuff_with(_: &mut u32) {}

struct Foobar<'a> {
    foo: &'a mut u32,
}

impl<'a> Foobar<'a> {
    fn consume(self) -> &'a mut u32 {
        do_complex_stuff_with(self.foo);
        self.foo
    }
}

fn create_then_drop_foobar(ptr: &mut u32) -> &mut u32 {
    let foobar = Foobar { foo: ptr };
    foobar.consume()
}

Edit: removed unnecessary muts.

6 Likes

In case it helps to split the question into two parts:

impl<'a> Foobar<'a> {
    // effectively &mut &'a mut u32 -> &'a mut u32
    fn borrow(&mut self) -> &'a mut u32 {

Not even &mut &mut u32 can do that; it's completely unsound.

impl<'a> Foobar<'a> {
    fn reborrow<'s>(&'s mut self) -> &'s mut u32
    where
        *self.foo remains borrowed for `'s` but self does not
        (to such an extent `*self` can be dropped without
         invalidating the returned reborrow)

There's no function signature that supports this today, but it's theoretically possible.[1] In the meanwhile, you can only achieve it by working on the field directly.


  1. Maybe one step beyond that really, &mut {*foo} self ↩ī¸Ž