从Box <dyn Trait1 + Trait2>返回&dyn Trait1

时间:2020-02-10 20:32:42

标签: rust

如果我有Box<dyn Trait1 + Trait2>,我可以返回&dyn Trait1吗?

为了提供一些背景信息,我正在尝试在rust中实现一个(专用)图。 SpecialisedGraph需要一些标准的图形算法,我想使用Graph特性来实现这些特性,这些特性可以在几种图形类型之间共享,但是此代码未编译:

trait Node {
    //...
}

trait Graph {
    fn get_node(&self, key: &str) -> Option<&dyn Node>;
}

trait SpecialisedNode {
    //...
}

trait SpecialisedGraphNode: SpecialisedNode + Node {}

struct SpecialisedGraph {
    nodes: HashMap<String, Box<dyn SpecialisedGraphNode>>
}

impl Graph for SpecialisedGraph {
    fn get_node(&self, key: &str) -> Option<&dyn Node> {
        match self.nodes.get(key) {
            Some(node) => Some(&(**node)),
            None => None
        }
    }
}

有错误:

error[E0308]: mismatched types
  --> src\main.rs:25:32
   |
25 |             Some(node) => Some(&(**node)),
   |                                ^^^^^^^^^ expected trait `Node`, found trait `SpecialisedGraphNode`
   |
   = note: expected reference `&dyn Node`
              found reference `&dyn SpecialisedGraphNode`

编辑:我已经编辑了问题以反映评论

EDIT2:使用Shepmaster提供的链接Why doesn't Rust support trait object upcasting?找到了我的问题的答案。

下面的更新代码现在可以使用了,谢谢。

trait AsNode {
    fn as_node(&self) -> &dyn Node;
}

trait Node : AsNode {
    //...
}

impl<T: Node> AsNode for T {
    fn as_node(&self) -> &dyn Node {
        self
    }
}

trait Graph {
    fn get_node(&self, key: &str) -> Option<&dyn Node>;
}

trait SpecialisedNode : Node {
    //...
}

struct SpecialisedGraph {
    nodes: HashMap<String, Box<dyn SpecialisedNode>>
}

impl Graph for SpecialisedGraph {
    fn get_node(&self, key: &str) -> Option<&dyn Node> {
        match self.nodes.get(key) {
            Some(node) => Some(node.as_node()),
            None => None
        }
    }
}

1 个答案:

答案 0 :(得分:2)

不能。 HashMap<String, Box<dyn SpecialisedGraphNode>不是HashMap<String, Box<dyn Node>,因此您无法形成对该类型的引用。如果使用不安全的代码执行此操作,则会调用未定义的行为,因为这些框没有相同的数据。

我也认为您的感觉是错误的-至少Java,C ++和C#(以最常见的静态类型OO语言命名)也不允许您这样做。 (使用C#,您可以对IReadOnlyDictionary进行类似的操作,并且通常对接口使用协变泛型参数。但对于具体类型则不行。)

您可能需要重新考虑自己的Graph特性。是否真的必须以哈希映射的形式授予对节点的访问权限?也许它可以简单地提供一个查询节点并将其返回为&dyn Node的功能?