56

I have a struct that has inner mutability.

use std::cell::RefCell;

struct MutableInterior {
    hide_me: i32,
    vec: Vec<i32>,
}
struct Foo {
    //although not used in this particular snippet,
    //the motivating problem uses interior mutability
    //via RefCell.
    interior: RefCell<MutableInterior>,
}

impl Foo {
    pub fn get_items(&self) -> &Vec<i32> {
        &self.interior.borrow().vec
    }
}

fn main() {
    let f = Foo {
        interior: RefCell::new(MutableInterior {
            vec: Vec::new(),
            hide_me: 2,
        }),
    };
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
}

Produces the error:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:16:10
   |
16 |         &self.interior.borrow().vec
   |          ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 |     }
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 | /     pub fn get_items(&self) -> &Vec<i32> {
16 | |         &self.interior.borrow().vec
17 | |     }
   | |_____^

The problem is that I can't have a function on Foo that returns a borrowed vec, because the borrowed vec is only valid for the lifetime of the Ref, but the Ref goes out of scope immediately.

I think the Ref must stick around because:

RefCell<T> uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCell<T>s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell<T> borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in task panic.

Now I could instead write a function like this that returns the entire interior:

pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;

However this potentially exposes fields (MutableInterior.hide_me in this example) that are really private implementation details to Foo.

Ideally I just want to expose the vec itself, potentially with a guard to implement the dynamic borrowing behavior. Then callers do not have to find out about hide_me.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Drew
  • 8,675
  • 6
  • 43
  • 41

5 Answers5

43

Instead of creating a brand new type, you can use Ref::map (since Rust 1.8). This has the same result as Levans' existing answer:

use std::cell::Ref;

impl Foo {
    pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}

You can also use new features like impl Trait to hide the Ref from the API:

use std::cell::Ref;
use std::ops::Deref;

impl Foo {
    pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • What about instead of get_item, if you were implementing the std::ops::Index<> trait, which requires you to return &Self::Output . Returning a std::cell::Ref, as far as I have been able to figure out, won't satisfy the trait requirement. Is there a way to do interior mutability with for that trait? – DanielV Oct 07 '19 at 21:52
  • Actually I found a way to do it with UnsafeCell, so I think maybe that will be good enough. – DanielV Oct 07 '19 at 22:05
  • 1
    @DanielV [Implementing Index trait to return a value that is not a reference](https://stackoverflow.com/q/39113649/155423). I wouldn't trust the `UnsafeCell` implementation because it's quite likely that it introduces memory unsafety. – Shepmaster Oct 08 '19 at 01:38
  • Note: `map` doesn't exist for `Mutex` meaning that this kind of thing is single-thread only (and from glancing at the code in both `cell.rs` and `mutex.rs` I think `MutexGuard` at a minimum would need to be redesigned to support such). I _think_ that it's possible to use a variant of @Levan's solution below in that case, but haven't tried it. – Kevin Anderson Mar 28 '23 at 16:18
34

You can create a new struct similar to the Ref<'a,T> guard returned by RefCell::borrow(), in order to wrap this Ref and avoid having it going out of scope, like this:

use std::cell::Ref;

struct FooGuard<'a> {
    guard: Ref<'a, MutableInterior>,
}

then, you can implement the Deref trait for it, so that it can be used as if it was a &Vec<i32>:

use std::ops::Deref;

impl<'b> Deref for FooGuard<'b> {
    type Target = Vec<i32>;

    fn deref(&self) -> &Vec<i32> {
        &self.guard.vec
    }
}

after that, update your get_items() method to return a FooGuard instance:

impl Foo {
    pub fn get_items(&self) -> FooGuard {
        FooGuard {
            guard: self.interior.borrow(),
        }
    }
}

and Deref does the magic:

fn main() {
    let f = Foo {
        interior: RefCell::new(MutableInterior {
            vec: Vec::new(),
            hide_me: 2,
        }),
    };
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
    let v: &Vec<i32> = &items;
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Levans
  • 14,196
  • 3
  • 49
  • 53
  • 4
    Is this the only/idiomatic way to do this? Seems like a bit of trouble... Though I suppose instead of a getItems() method, you could borrow the internals in a block directly where it would then go out of scope (or something...) – norcalli Apr 02 '15 at 08:37
  • 3
    @Norcalli In the specific case of `RefCell`, the object needs to be notified when the reference goes out of scope (that's what the destructor of `Ref` does). Here, we need to preserve this behavior (the error of the OP was due to the `Ref` instance being dropped too early), and thus encapsulate it. – Levans Apr 02 '15 at 08:40
5

You can wrap the Vec in an Rc.

use std::cell::RefCell;
use std::rc::Rc;

struct MutableInterior {
    hide_me: i32,
    vec: Rc<Vec<i32>>,
}
struct Foo {
    interior: RefCell<MutableInterior>,
}

impl Foo {
    pub fn get_items(&self) -> Rc<Vec<i32>> {
        self.interior.borrow().vec.clone() // clones the Rc, not the Vec
    }
}

fn main() {
    let f = Foo {
        interior: RefCell::new(MutableInterior {
            vec: Rc::new(Vec::new()),
            hide_me: 2,
        }),
    };
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
}

When you need to mutate the Vec, use Rc::make_mut to obtain a mutable reference to the Vec. If there are still other Rcs referring to the Vec, make_mut will dissociate the Rc from the other Rcs, clone the Vec and update itself to refer to that new Vec, then give you a mutable reference to it. This ensures that the value in the other Rcs doesn't suddenly change (because Rc by itself doesn't provide interior mutability).

Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
2

Ref<X> is the usual answer. However, sometimes, such as when designing a trait, a consistent interface is required. For instance a trait with:

fn get_x(&self) -> &X

will preclude structs storing x in a RefCell<X>, while:

fn get_x(&self) -> Ref<X>

will preclude structs storing x as a plain X.

A pattern that can be used to get around this is to instead take a method which operates on the data.

fn with_x(&self, fun : &dyn FnOnce(&X));

Which works with both classes using X and RefCell<X> (or any other composition for that matter):

fun(&self.x);
// or
fun(&self.x.borrow());
c z
  • 7,726
  • 3
  • 46
  • 59
1

If you really must return a reference to the data (as in an external crate requires some interface or similar) you can do so with Rc::leak, which currently requires nightly, until it stabilizes you can help yourself with this little function:

use std::cell::Ref;
fn leak_ref<'a, T>(orig: Ref<'a, T>) -> &'a T {
    Box::leak(Box::new(orig))
}

The same disclaimer as for the original leak applies here to:

The underlying RefCell can never be mutably borrowed from again and will always appear already immutably borrowed. It is not a good idea to leak more than a constant number of references. The RefCell can be immutably borrowed again if only a smaller number of leaks have occurred in total.

cafce25
  • 15,907
  • 4
  • 25
  • 31