Rust Rc<;特质>;选择<;T>;?
我正在尝试实现一个如下所示的方法:Rust Rc<;特质>;选择<;T>;?,rust,trait-objects,Rust,Trait Objects,我正在尝试实现一个如下所示的方法: fn concretify<T: Any>(rc: Rc<Any>) -> Option<T> { Rc::try_unwrap(rc).ok().and_then(|trait_object| { let b: Box<Any> = unimplemented!(); b.downcast().ok().map(|b| *b) }) } 但是,Rc::in
fn concretify<T: Any>(rc: Rc<Any>) -> Option<T> {
Rc::try_unwrap(rc).ok().and_then(|trait_object| {
let b: Box<Any> = unimplemented!();
b.downcast().ok().map(|b| *b)
})
}
但是,Rc::into_raw()
似乎要求Rc
中包含的类型大小为size
,理想情况下,我不希望必须使用不安全的块
有什么方法可以实现这一点吗
,我在这里寻找rc_to_box
的实现。如果您希望将原始值移出rc
,我认为不可能实现您的具体化
功能;看看原因
如果您愿意返回克隆,很简单:
fn concretify<T: Any+Clone>(rc: Rc<Any>) -> Option<T> {
rc.downcast_ref().map(Clone::clone)
}
fn具体化(rc:rc
如果您想要更“动态”的东西,并且创建值很便宜,您也可以制作一个虚拟对象,使用downcast\u mut()
而不是downcast\u ref()
,然后使用虚拟对象交换std::mem::swap
。不幸的是,Rc
的API似乎缺少必要的方法,无法在!size
时获得包装类型的所有权
唯一可以返回Rc
内部项的方法是Rc::try_unwrap
,但是它返回结果
,这要求T
的大小为size
为了做你想做的事情,你需要一个带有签名的方法:Rc->Result
,它允许T
被!调整大小,从那里你可以提取框
,并执行向下转换
调用
然而,由于Rc
是如何实现的,这种方法是不可能的
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
pub struct Rc<T: ?Sized> {
ptr: *mut RcBox<T>,
_marker: PhantomData<T>,
}
这里有一个不和谐:选项
拥有T
,而Rc
只是对象的共同所有者之一。我可以看到两种处理方法:如果有多个所有者,则返回无
,或者将函数从&Rc
转换为选项
。第一种方法真的是你想要的吗想要?这就是它的用途--它确保给定的Rc
是唯一的所有者。“concretify
”应该返回None
,如果有多个所有者或者Any
不是T
。在这种情况下,只需检查:),你同意None
吗,还是更愿意返回一个结果
,在其Err
字段中指定问题是类型不匹配还是多个所有者?如果我是一个更好的人,我想要结果
:)如果只有结果
才可能,我当然会接受这一点,但我相对确定问题的语义是相同的,不管我使用的是选项
、结果
,还是恐慌!(“坏事情发生了,伙计们”)
是的,这只是一个表面上的改变:)恐怕我不确定链接问题的哪一部分阻止了框的功能。我正在尝试(此时)将Rc
转换为Box
。(编辑问题以澄清这一点)嗯,我总是忘记任何
文档的一部分在框下
!说得好,不清楚,现在我不太确定;我等会儿再看看能否改进我的答案。
#[derive(Debug,Clone)]
struct Foo(u32);
#[derive(Debug,Clone)]
struct Bar(i32);
fn main() {
let rc_foo: Rc<Any> = Rc::new(Foo(42));
let rc_bar: Rc<Any> = Rc::new(Bar(7));
let foo: Option<Foo> = concretify(rc_foo);
println!("Got back: {:?}", foo);
let bar: Option<Foo> = concretify(rc_bar);
println!("Got back: {:?}", bar);
}
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
pub struct Rc<T: ?Sized> {
ptr: *mut RcBox<T>,
_marker: PhantomData<T>,
}
use std::any::Any;
use std::{cell, mem, ptr};
use std::rc::Rc;
struct RcBox<T: ?Sized> {
strong: cell::Cell<usize>,
_weak: cell::Cell<usize>,
value: T,
}
fn concretify<T: Any>(rc: Rc<Any>) -> Option<T> {
// Will be responsible for freeing the memory if there is no other weak
// pointer by the end of this function.
let _guard = Rc::downgrade(&rc);
unsafe {
let killer: &RcBox<Any> = {
let killer: *const RcBox<Any> = mem::transmute(rc);
&*killer
};
if killer.strong.get() != 1 { return None; }
// Do not forget to decrement the count if we do take ownership,
// as otherwise memory will not get released.
let result = killer.value.downcast_ref().map(|r| {
killer.strong.set(0);
ptr::read(r as *const T)
});
// Do not forget to destroy the content of the box if we did not
// take ownership
if result.is_none() {
let _: Rc<Any> = mem::transmute(killer as *const RcBox<Any>);
}
result
}
}
fn main() {
let x: Rc<Any> = Rc::new(1);
println!("{:?}", concretify::<i32>(x));
}