残念ながら、 の API にRc
は、 の場合にラップされた型の所有権を取得できるようにするために必要なメソッドが欠けているようです!Sized
。
a の内部アイテムを返すメソッドは だけRc
ですが、 beが必要なメソッドがRc::try_unwrap
返されます。Result<T, Rc<T>>
T
Sized
あなたが望むことをするためには、署名付きのメソッドが必要です:Rc<T> -> Result<Box<T>, Rc<T>>
であることがT
でき!Sized
、そこから呼び出しを抽出Box<Any>
して実行できdowncast
ます。
Rc
ただし、実装方法により、この方法は不可能です。以下は、 の簡略版です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>,
}
したがって、Box
あなたが抜けられるのRc<T>
はだけですBox<RcBox<T>>
。
ここでは設計が厳しく制限されていることに注意してください。
- 単一割り当てでは、3 つの要素すべてが単一にあることが義務付けられています。
struct
T: ?Sized
T
最後のフィールドである命令
そのため、一般的に改善の余地はほとんどありません。
ただし、特定のケースでは、一般的な状況を改善することは間違いなく可能です。もちろん、コードが必要unsafe
です。また、 でかなりうまく機能しますがRc
、 での実装Arc
は潜在的なデータ競合によって複雑になります。
ああ...そしてコードはそのまま提供され、保証はありません;)
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));
}