Reputation: 115
We know that it's easy to convert a value of type RefCell<T>
to a value of type &T
for use as a parameter in a function:
fn main() {
let a: RefCell<i32> = RefCell::new(0);
my_func(a.borrow().deref());
}
fn my_func(i: &i32) {}
In my scenario, the RefCell
s are stored in a HashMap
, so they get obtained wrapped in an Option
. I also want the function I pass them to have the notion of option, but I only want to pass the non-mutable reference, not the whole RefCell
. We can achieve this like so:
fn main() {
let a: Option<RefCell<i32>> = Some(RefCell::new(0));
match a {
Some(ref_cell) => my_func(Some(ref_cell.borrow().deref())),
None => my_func(None)
};
}
fn my_func(i: Option<&i32>) {}
This works, but in my specific scenario, my_func
takes several of these Option<&T>
s as a parameter, so doing it this way means the match
just gets nested for each parameter and grows exponentially. It would therefore be helpful to have someway of doing this:
fn main() {
let a: Option<RefCell<i32>> = Some(RefCell::new(0));
let c = match a {
Some(ref_cell) => Some(ref_cell.borrow().deref()), // won't compile as this borrow won't live long enough
None => None
};
my_func(c);
}
fn my_func(i: Option<&i32>) {}
So essentially I want to be able to convert from Option<RefCell<T>>
to Option<&T>
. I feel like this should be possible somehow but I can't figure out a way to do it. I always run into some issue of performing the .borrow()
on the RefCell
but it not living long enough.
Upvotes: 2
Views: 596
Reputation: 60062
You can do this using the methods on Option
:
a.as_ref().map(RefCell::borrow).as_deref()
as_ref()
is used to convert the Option<RefCell<_>>
into a Option<&RefCell<_>>
to avoid consuming it. If you already have a Option<&RefCell<_>>
because you got it from hash_map.get()
or similar, then you can skip this.map(RefCell::borrow)
is used to call .borrow()
on the value if it exists. This will create a Option<Ref<'_, _>>
.as_deref()
is the equivalent of calling .deref()
on the value if it exists.It is important to do it this way instead of trying to merge the .borrow()
and .deref()
in a single .map()
call because this keeps the intermediate Ref<'_, _>
value alive.
a.as_ref().map(|a| a.borrow().deref())
error[E0515]: cannot return reference to temporary value
--> src/main.rs:8:24
|
8 | a.as_ref().map(|a| a.borrow().deref())
| ----------^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
Also, if have multiple parameters like this and you want to split them out into variables, be sure to take the Ref<'_, _>
part on its own and use .as_deref()
where you use it. Again this is needed to keep the intermediate Ref<'_, _>
alive:
let a_ref = a.as_ref().map(RefCell::borrow);
let b_ref = b.as_ref().map(RefCell::borrow);
let c_ref = c.as_ref().map(RefCell::borrow);
f(a_ref.as_deref(), b_ref.as_deref(), c_ref.as_deref());
Upvotes: 7