2

我需要编写一个函数foo,它接受 a &RefCell<Box<dyn Any>>,从 中借用RefCell并返回一个向下转换的对象。向下转换的类型是在运行时选择的,但对于这个例子,我们假设它是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());
}

我尝试foo这样实现:

// 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)
}

这个版本的问题是它假设它downcast_ref总是有效的,但我想发现一个downcast_ref错误。下面我尝试以foo一种可以捕获错误的方式实现:

// 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)
}

这个版本可以捕获 downcast 错误,但它必须调用downcast_ref两次(这可以接受,但我想知道是否有更好的方法)。当尝试downcast_ref只使用一次时,我遇到了终身错误。

4

1 回答 1

2

经过一番修改,我想出了这个解决方案。您可以使用Any::is<T>()在映射之前检查借用。

pub fn foo<T: 'static>(cell: &RefCell<Box<dyn Any>>) -> Option<Ref<T>> {
    let borrowed = cell.borrow();
    
    if borrowed.is::<T>() {
        Some(Ref::map(borrowed, |x| x.downcast_ref::<T>().unwrap()))
    } else {
        None
    }
}

锈游乐场链接

于 2020-10-12T01:02:18.780 回答