【问题标题】:Sharing weak trait object references共享弱特征对象引用
【发布时间】:2019-01-08 07:27:01
【问题描述】:

我正在尝试提供非拥有结构的“视图”来分离系统的组件。

假设一组具有不同方法的特征:DrawableModifiable 和许多实现至少一个特征的结构 - SimpleBoxPanelExpression

系统的不同组件需要频繁访问这些对象的序列,使用特定特征的方法;考虑DrawingManagerModifyManager

struct DrawingManager {
    items: Vec<Weak<Drawable>>,
}

struct ModifyManager {
    items: Vec<Weak<Modifiable>>
}

虽然可以在两个管理器中引用单个对象,但假设所有结构都有一个单独的所有者:

struct ObjectManager {
    boxes: Vec<Rc<Box>>,
    panels: Vec<Rc<Panel>>,
    expressions: Vec<Rc<Expression>>,
}

理想情况下,能够管理从一个位置删除结构会很有用 - 即只需将其从 ObjectManager 中删除就足以使所有其他组件中的引用无效(因此使用 Weak)。

  • 有没有办法做到这一点?
  • 这是实现此目的的正确方法吗?
  • 是否有更惯用的方式来实现此功能?

该系统包含多个特征,因此使用所有其他特征的方法制作单个特征似乎是个坏主意。几个 trait 有不止一种方法,所以用闭包替换它们是不可能的。

我的尝试

由于一个对象可能产生一个或多个Rc&lt;Trait&gt;,我们可以设想用HashMap&lt;ID, Vec&lt;Rc&lt;Any&gt;&gt;&gt; 来实现这一点,从而我们使每个结构都有一个唯一的ID,它映射到所有Rc 的列表为它而生。

当我们想要移除一个对象时,我们将它从对应的列表中移除,并移除hashmap中的条目,使所有Weak引用失效。

但是,执行此操作失败,因为要插入HashMap,必须向上转换Rc&lt;Trait&gt; -> Rc&lt;Any&gt;,稍后才能向下转换。

【问题讨论】:

  • 有没有办法做到这一点?这是实现这一目标的正确方法吗? 有点矛盾。您拥有的解决方案是否符合您的要求?如果不是,那有什么问题?
  • 对不起,我的措辞不清楚。我没有编译解决方案。
  • 虽然您可以通过克隆转换一个Rc&lt;struct&gt; -&gt; Rc&lt;Trait&gt;,然后使用Rc::downgrade 将对该Weak&lt;Trait&gt; 的引用转换为Weak&lt;Trait&gt;,但我还没有找到一种合适的方法来首先存储@987654345 @ 转换为超类型的序列(例如Vec&lt;Rc&lt;Any&gt;&gt;,然后将对超类型的引用向下转换为对原始类型的引用(&amp;Rc&lt;Any&gt; -&gt; &amp;Rc&lt;Trait&gt;)。
  • 我至少已经回答了 two questions 关于 Rust 中的向下转换。我在想另一个(不是我写的),但我现在找不到。其中之一能回答你的问题吗?
  • 这个问题的主要要点不是向下转换 - 而是获得 Weak 引用 - 这提供了两个重要功能 - 维护数据的单个“所有者”,同时还允许处理多个引用相同的 - 即持有vec&lt;Weak&lt;Trait&gt;&gt; 的序列,而不是每个独立类型的多个列表。碰巧在我的示例中,我遇到了向下转换的问题(但只是因为我之前立即向上转换)。

标签: rust traits trait-objects


【解决方案1】:

我不确定这是否是惯用的做法,但我已经开发了一个提供此功能的板条箱 - dependent_view

使用 crate,最初的问题可以通过使用 DependentRc 而不是普通的 Rc's 来解决:

struct ObjectManager {
    boxes: Vec<DependentRc<Box>>,
    panels: Vec<DependentRc<Panel>>,
    expressions: Vec<DependentRc<Expression>>
}

let object_manager : ObjectManager = ObjectManager::new();

然后使用 crate 提供的宏,我们可以获得Weak&lt;&gt; 对这些结构体的引用:

let box_view : Weak<Drawable> = to_view!(object_manager.boxes[0]);
let panel_view : Weak<Drawable> = to_view!(object_manager.panels[0]);
let expression_view : Weak<Drawable> = to_view!(object_manager.expressions[0]);

这样,删除相应的DependentRc&lt;&gt; 将使所有对它的Weak&lt;&gt; 引用无效。

【讨论】:

    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2012-08-11
    • 2017-08-25
    • 1970-01-01
    相关资源
    最近更新 更多