Sometimes I have a struct
containing a value which is wrapped in a RefCell
, and I want to borrow the value, but I don't want to make the signature of the accessor function to depend on the internal implementation. To make it work, I need to return the reference as a Ref<T>
instead of a &T
.
For example, if this is my struct:
use std::cell::RefCell;
pub struct Outer<T> {
inner: RefCell<T>,
}
I could write an accessor like this:
use std::cell::Ref;
impl<T> Outer<T> {
fn get_inner_ref(&self) -> Ref<T> {
self.inner.borrow()
}
}
This works fine. I can use it like this:
fn main() {
let outer = Outer { inner: RefCell::new(String::from("hi")) };
let inner: &str = &outer.get_inner_ref();
println!("inner value = {:?}", inner);
}
However, this exposes Ref
as part of the public API, which would make it harder to change the internals later, without breaking backwards compatibility.
If I try change the signature to return an &T
— which &Ref<T>
can coerce to — then I get lifetime errors:
impl<T> Outer<T> {
fn get_inner_ref(&self) -> &T {
&self.inner.borrow()
}
}
The error is:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.inner.borrow()
| ^^^^^^^^^^^^^^^^^^^ 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 | / fn get_inner_ref(&self) -> &T {
16 | | &self.inner.borrow()
17 | | }
| |_____^
There doesn't appear to be a way to fix that, because the error message is correct. The code is trying to take a reference to the Ref<T>
, which only lasts as long as the function call. To make this work, I'd have to move out the Ref<T>
itself by returning it — exactly like in the original code above — rather than making a new reference to it.
There is an answer to How do I return a reference to something inside a RefCell without breaking encapsulation? which would technically solve this, but it is a more specialised case (to get only a part of the value in the RefCell
) and the solution seems overly complex for this simpler situation.