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