【问题标题】:Map from Rc<RefCell<T>> to Ref<'_, U>从 Rc<RefCell<T>> 映射到 Ref<'_, U>
【发布时间】:2020-05-14 22:14:29
【问题描述】:

我有以下结构:

struct Inner;

enum State {
    A(Inner),
    B,
}

struct Owner {
    state: Rc<RefCell<State>>,
}

我想提供如下接口:

impl Owner {
    fn a(&self) -> Option<Ref<'_, Inner>>;
}

owner.a() 将返回的位置:

  • owner.state 匹配State::A(s),然后Some([some ref to s])(这会增加owner.state 的强计数并在丢弃时减少它,同时保证RefCell 借用属性);
  • 否则,None

这有可能吗?我试过查看Ref::map,但似乎无法使其与Rc&lt;RefCell&lt;_&gt;&gt;Option 一起使用。

我现在正在做的解决方法是:

impl Owner {
    fn with_a(&self, mut callback: impl FnMut(&Inner)) {
        match *self.state.borrow() {
            State::A(ref inner) => callback(inner),
            _ => {}
        }
    }
}

playground

【问题讨论】:

  • 您提到想要增加 Rc 的计数,但fn a(&amp;self) -&gt; Option&lt;Ref&lt;'_, Inner&gt;&gt;; 无论如何都会将 ref 的生命周期与 Rc 绑定,因此无需增加计数。如果您发布的函数签名更符合您的要求,play.rust-lang.org/… 将起作用。
  • @loganfsmyth 我错过了unreachable! 部分,谢谢!

标签: rust reference borrow-checker reference-counting borrowing


【解决方案1】:

owner.a() 不需要增加Rc 的强计数,因为返回的Ref 的生命周期已经与Rc 相关联。如果您使用 100% Safe Rust 并且它可以编译,那么您将不会遇到任何内存安全问题,因此您不必担心手动记账,例如显式增加或减少 Rc 的强计数。 Rc 甚至没有公开更改强计数的方法,这是有充分理由的。这是您想要的函数签名的实现:

use std::rc::Rc;
use std::cell::{RefCell, Ref};

struct Inner;

enum State {
    A(Inner),
    B,
}

struct Owner {
    state: Rc<RefCell<State>>,
}

impl Owner {
    fn a(&self) -> Option<Ref<'_, Inner>> {
        let state_ref = self.state.borrow();
        match *state_ref {
            State::B => None,
            _ => Some(Ref::map(state_ref, |state| match state {
                State::A(inner) => inner,
                _ => unreachable!(),
            })),
        }
    }
}

playground

【讨论】:

  • 成功了!我还发现ref_map_filter crate 可以避免双重匹配。将此标记为已接受的答案,因为我无法接受@loganfsmyth 的评论。
猜你喜欢
  • 2019-12-13
  • 2023-01-20
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多