是否可以映射Rc <t>以获得Rc <subpart-of-t>?

时间:2019-01-15 23:38:47

标签: rust reference-counting

我有一个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可以只是在内部为新的映射值增加它的计数器,但是我找不到任何文档。

3 个答案:

答案 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)

不支持Rc。

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共享一个生存期,因此它的寿命可以更长。