Гетерогенные контейнеры в Rust для графа - PullRequest
2 голосов
/ 09 февраля 2020

Я программист C ++, изучающий Rust, и один из моих основных вариантов использования - это механизм вычислений на основе графов. В моем графе я храню однородный тип, а затем я получаю из него более конкретный тип c, например, в C ++

class BaseNode {
  public:
    BaseNode(std::vector<std::shared_ptr<BaseNode>>& parents);
    virtual ~BaseNode() = default;

    virtual void update(); 
    const std::vector<std::shared_ptr<BaseNode>>& parents() const;
    ...
};

template<typename T>
class TypedNode<T> : public BaseNode {
  public:
    const T& value() const { return value_; }

    ...
  private:
    T value_;
}

Идея состоит в том, что граф пересекается и вызывается update() на каждом узле. Узел знает, что такое каждый из его «истинных типов» своих родителей, и поэтому в update() может сделать что-то вроде static_cast<TypedNode<DataBlob>>(parents()[0]).

Как мне добиться чего-то подобного в Rust?

Я думал о дизайне, подобном этому:

trait BaseNode {
    fn parents(&self) -> &Vec<dyn BaseNode>;
}

trait TypedNode<T>: BaseNode {
    fn value(&self) -> &T;
}

Но я читал, что не смогу преобразовать «объект черты» из BaseNode в TypedNode<T>. (Или я могу сделать это как-нибудь, используя unsafe?). Другая альтернатива, о которой я подумал, - иметь структуру, которая хранит данные в Any, а затем преобразовать их, но стоит ли это некоторых затрат времени выполнения?

1 Ответ

0 голосов
/ 10 февраля 2020

Если родители всех узлов имеют одинаковый тип, вы можете использовать этот подход:

trait BaseNode {
    type Parent: BaseNode;
    fn parents(&self) -> &[Self::Parent];
}

trait TypedNode<P: BaseNode>: BaseNode<Parent = P> {
    type ValueType;
   fn value(&self) -> &Self::ValueType;
}

Rust Playground

Я не уверен, понимаю ли я ваше вопрос. Пожалуйста, дайте мне знать, если это не сработает для вас.

...