我有一个Rc<Option<T>>
,但需要从中获取一个Rc<T>
。像这样:
let rc_option: Rc<Option<T>> = Rc::new(Ok(value));
let ok_value: Rc<T> = rc_option.map(|option| option.unwrap());
这甚至可以实现吗?似乎应该是有道理的,因为Rc
可以只是在内部为新的映射值增加它的计数器,但是我找不到任何文档。
答案 0 :(得分:7)
否,不可能从Rc<T>
创建Rc<Option<T>>
来使后者仍然存在。可以从Rc<&T>
创建一个Rc<Option<T>>
,同时仍然保留后者。
如果您要创建一个在Rc<T>
内部拥有T
的新Rc<Option<T>>
,则必须使用原始的Rc<Option<T>>
。您也不能拥有Rc<Option<T>>
的多个实例,因为那样的话,您将在指针仍然存在的同时移动共享值,这是非常不安全的。
但是有一种方法可以安全地执行此操作!使用Rc::try_unwrap
,您可以尝试将值移出,但是如果存在原始Rc
的多个实例,则将返回错误。
请记住,您还必须处理Option<T>
最终成为None
的情况。
这是一个例子:
let rc_option: Rc<Option<T>> = Rc::new(Some(value));
match Rc::try_unwrap(rc_option) {
Ok(option) => {
match option {
Some(t) => {
let ok_value: Rc<T> = Rc::new(t);
// Do something with ok_value
}
None => {
// Do something else here
}
}
}
Err(rc_option) => {
// There are multiple owners, do something else here
}
}
如果您想保留原件,可以执行以下操作:
match &*rc_option {
Some(ref t) => {
let ok_ref: Rc<&T> = Rc::new(t);
}
None => { /* Do something else, there's no internal value */ }
}
编辑:如Chronial所述,请注意ok_ref
不能超过rc_option
(因为它是对rc_option
的引用),这可能不是您想要的。
答案 1 :(得分:2)
var token = PubSub.subscribe(user_id, commandResponse);
仅仅因为其内存布局是不可能的:
PubSub.publish(userId, message);
因此,计数器应位于Rc
旁边,因此您不能在两个不同的元素之间共享计数器。
从内存布局的角度来看,完全可以创建备用// Equivalence:
struct RcBox<T> {
strong: AtomicUsize,
weak: AtomicUsize,
data: T,
};
struct Rc<T> {
ptr: *const RcBox<T>,
};
:
T
从理论上讲,这可以允许进行映射...但是在其上创建安全的接口可能并不容易。
如何防止用户返回FlexRc
中无关的生存期?是否保证返回引用的生存期超过struct Counters {
strong: AtomicUsize,
weak: AtomicUsize, // if support for FlexWeak is desired.
ptr: *mut (),
drop: fn(*mut ()),
}
struct FlexRc<T> {
counters: *mut Counters,
ptr: *const T,
}
的生存期就足够安全了?
map
答案 2 :(得分:1)
正如That their answer中所述,标准库不支持。您可以自己实现这样的功能:
use std::ops::Deref;
#[derive(Clone)]
struct RcSome<T>(Rc<Option<T>>);
impl<T> RcSome<T> {
fn from(rc: &Rc<Option<T>>) -> RcSome<T> {
RcSome(rc.clone())
}
}
impl<T> Deref for RcSome<T> {
type Target = T;
fn deref(&self) -> &T {
self.0.as_ref().as_ref().unwrap()
}
}
那你就可以做到
let rc_option: Rc<Option<T>> = Rc::new(Some(value));
let ok_value: RcSome<T> = RcSome::from(&rc_option);
请注意,如果rc_option
包含None
,将会引起恐慌。但是ok_value
现在的行为类似于Rc<T>
–即您可以clone()
进行ok_value.some_method_of_T()
。 ok_value
也不与rc_option
共享一个生存期,因此它的寿命可以更长。