I need to write a function foo
that takes a &RefCell<Box<dyn Any>>
, borrows from the RefCell
and returns a downcasted object. The downcasted type is chosen at runtime, but for this example let's assume it's usize
.
use core::any::Any;
use std::cell::{RefCell, Ref};
pub fn foo<T: 'static>(cell: &RefCell<Box<dyn Any>>) -> Option<Ref<Box<T>>> {
???
}
pub fn main() {
let boxed: Box<dyn Any> = Box::new(1 as usize);
let cell = RefCell::new(boxed);
let num = foo(&cell);
println!("x: {}", num.unwrap());
}
I tried implementing foo
like this:
// 1:
pub fn foo<T: 'static>(cell: &RefCell<Box<dyn Any>>) -> Option<Ref<Box<T>>> {
let borrowed_cell = Ref::map(cell.borrow(), |borrow| borrow.downcast_ref::<T>().unwrap());
Some(borrowed_cell)
}
The problem with this version is that it assumes that downcast_ref
will always work, but I would like to catch a downcast_ref
error.
Below I try to implement foo
in a way that I can catch the error:
// 2:
pub fn foo<T: 'static>(cell: &RefCell<Box<dyn Any>>) -> Option<Ref<T>> {
{
cell.borrow().downcast_ref::<T>()?;
}
let borrowed_cell = Ref::map(cell.borrow(), |borrow| borrow.downcast_ref::<T>().unwrap());
Some(borrowed_cell)
}
This version can catch the downcast error, but it has to call downcast_ref
twice (which could be acceptable, but I am wondering if there is a better way). When trying to use downcast_ref
only once, I got stuck with lifetime errors.
After a bit of tinkering with it, I came up with this solution. You can make use of
Any::is<T>()
to check the borrow before mapping it.Rust Playground link