web-dev-qa-db-ja.com

グラフのようなデータ構造をRust

リンクにはメタデータが含まれているため、リンクオブジェクトにリンクされたいくつかの構造体間の単方向グラフとして表すことができるデータ構造があります。

これは次のようになります。

struct StateMachine {
    resources: Vec<Resource>,
    links: Vec<Link>,
}
struct Resource {
    kind: ResourceType,
      // ...
}

enum LinkTarget {
    ResourceList(Vec<&Resource>),
    LabelSelector(HashMap<String, String>),
}

struct Link {
    from: LinkTarget,
    to: LinkTarget,
    metadata: SomeMetadataStruct,
}

実行時にリンクとリソースを追加および削除できる必要があるため、構造全体を変更可能にする必要があります。このため、通常のライフタイムモデルを使用して、リソースを親構造体のライフタイムにバインドすることはできません。

適切なタイプを選択することで 「自分の保証を選択する」 が必要であることは理解していますが、この問題を解決する最善の方法がわかりません。

16
Lorenz

実際、グラフのような構造の場合、最も簡単な解決策は、 TypedArena などのアリーナを使用することです。

ノードの存続期間は、ノードが作成された型付きアリーナのインスタンスの存続期間のみに依存するため、リソース管理が大幅に簡素化されます。

警告:ノードがグラフに動的に追加/削除されるシナリオは避けてください。アリーナが削除されるまでノードはアリーナから削除されません。そのため、アリーナのサイズは無制限に拡大します。


実行時にノードを追加/削除する状況にある場合、別の解決策は次のとおりです。

  • Resourcesのコレクションがあります
  • エッジがResourcesを間接的にのみ参照するようにする(所有者でも借り手でもない)

2つの例:

  • HashMap<ResourceId, (Resource, Vec<ResourceId>)>
  • _type R = RefCell<Resource>_、_Vec<Rc<R>>_およびVec<(Weak<R>, Vec<Weak<R>>)>

いずれの場合も、リソースを削除するときにエッジをクリーンアップする責任があります。忘れると、メモリリークやパニック(間接参照時)が発生する可能性がありますが、それ以外の場合は安全です。

おそらく、上記には無限のバリエーションがあります。

10
Matthieu M.

Rustでのグラフのような構造のモデリングは単純な問題ではありません。ここでは、NickCameronとNikoMatsakisからの2つの貴重な議論があります(Mozillaの2つの主要なRust開発者) 。)

グラフとアリーナの割り当て

Rustベクトルインデックスの使用 でのグラフのモデリング

12
eulerdisk

グラフのような構造の最も簡単な解決策は、グラフをモデル化するライブラリを使用することです。 petgraph は良い選択です:

extern crate petgraph;

use std::rc::Rc;
use std::collections::HashMap;

use petgraph::Graph;

struct Resource;

enum LinkTarget {
    ResourceList(Vec<Rc<Resource>>),
    LabelSelector(HashMap<String, String>),
}

struct SomeMetadataStruct;

fn main() {
    let mut graph = Graph::new();

    let n1 = graph.add_node(LinkTarget::LabelSelector(Default::default()));
    let n2 = graph.add_node(LinkTarget::LabelSelector(Default::default()));

    let l2 = graph.add_Edge(n1, n2, SomeMetadataStruct);
}

ここで選択する必要がある保証は、ResourceListのメンバーを中心にしています。シングルスレッドの共有不変Resourcesが必要だと思います。

  • スレッド間で共有する必要がある場合は、Vec<Arc<Resource>>を使用してください
  • 共有されていない場合は、所有しているだけです— Vec<Resource>
  • 変更可能にする必要がある場合は、Vec<Rc<RefCell<Resource>>>(またはマルチスレッドの場合はMutex)を使用します
5
Shepmaster