2

Petgraph implements all its traits for references to it's internal graph type. How can I store and use a Graph rather than an &Graph in a struct?

This works but stores a reference to the graph:

extern crate petgraph;

use crate::petgraph::visit::*;
use petgraph::data::*;
use petgraph::*;

struct StateMachine<G>
where
    G: GraphBase,
{
    state_network: G,
    state: <G as GraphBase>::NodeId,
}

impl<G> StateMachine<G>
where
    G: IntoNodeReferences
        + IntoEdgeReferences
        + IntoEdges
        + Data
        + NodeIndexable
        + GraphProp
        + DataMap
        + GraphBase,
    <G as Data>::NodeWeight: Eq + Copy,
    <G as Data>::EdgeWeight: Eq + Copy,
{
    pub fn next(&mut self, input: <G as Data>::EdgeWeight) -> Option<<G as Data>::NodeWeight> {
        for edge in self.state_network.edges(self.state) {
            if *edge.weight() == input {
                self.state = edge.target();
                return match self.state_network.node_weight(self.state) {
                    Option::Some(weight) => Some(*weight),
                    Option::None => Option::None,
                };
            }
        }
        return Option::None;
    }

    pub fn new(network: G, start: <G as Data>::NodeWeight) -> Option<StateMachine<G>> {
        for nr in network.node_references() {
            if *(network.node_weight(nr.id())).unwrap() == start {
                return Option::Some(StateMachine {
                    state_network: network,
                    state: nr.id(),
                });
            }
        }
        return Option::None;
    }
}

fn main() {
    let mut sn: Graph<&str, u32, petgraph::Directed> = Graph::new();
    let sn_item1 = sn.add_node("a");
    let sn_item2 = sn.add_node("b");
    let sn_item3 = sn.add_node("c");
    let sn_item4 = sn.add_node("d");
    let sn_item5 = sn.add_node("e");
    sn.add_edge(sn_item1, sn_item2, 1);
    sn.add_edge(sn_item1, sn_item3, 2);
    sn.add_edge(sn_item2, sn_item4, 1);
    sn.add_edge(sn_item2, sn_item5, 2);
    sn.add_edge(sn_item5, sn_item1, 2);
    sn.add_edge(sn_item5, sn_item3, 1);
    let mut sm = StateMachine::new(&sn, "a").unwrap();
    println!("{}", sm.next(1).unwrap());
}

Link to rust playground

But storing the Graph directly doesn't work

extern crate petgraph;

use crate::petgraph::visit::*;
use petgraph::data::*;
use petgraph::*;

struct StateMachine<'a, G>
where
    &'a G: GraphBase,
{
    state_network: G,
    state: <&'a G as GraphBase>::NodeId,
}

impl<'a, G> StateMachine<'a, G>
where
    &'a G: IntoNodeReferences
        + IntoEdgeReferences
        + IntoEdges
        + Data
        + NodeIndexable
        + GraphProp
        + DataMap
        + GraphBase,
    <&'a G as Data>::NodeWeight: Eq + Copy,
    <&'a G as Data>::EdgeWeight: Eq + Copy,
{
    pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
        for edge in (&self.state_network).edges(self.state) {
            if *edge.weight() == input {
                self.state = edge.target();
                return match (&self.state_network).node_weight(self.state) {
                    Option::Some(weight) => Some(*weight),
                    Option::None => Option::None,
                };
            }
        }
        return Option::None;
    }

    pub fn new(network: G, start: <&'a G as Data>::NodeWeight) -> Option<StateMachine<'a, G>> {
        for nr in network.node_references() {
            if *((&network).node_weight(nr.id())).unwrap() == start {
                return Option::Some(StateMachine {
                    state_network: network,
                    state: nr.id(),
                });
            }
        }
        return Option::None;
    }
}

fn main() {
    let mut sn: Graph<&str, u32, petgraph::Directed> = Graph::new();
    let sn_item1 = sn.add_node("a");
    let sn_item2 = sn.add_node("b");
    let sn_item3 = sn.add_node("c");
    let sn_item4 = sn.add_node("d");
    let sn_item5 = sn.add_node("e");
    sn.add_edge(sn_item1, sn_item2, 1);
    sn.add_edge(sn_item1, sn_item3, 2);
    sn.add_edge(sn_item2, sn_item4, 1);
    sn.add_edge(sn_item2, sn_item5, 2);
    sn.add_edge(sn_item5, sn_item1, 2);
    sn.add_edge(sn_item5, sn_item3, 1);
    let mut sm = StateMachine::new(sn, "a").unwrap();
    println!("{}", sm.next(1).unwrap());
}

Link to rust playgound

  Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:29:21
   |
29 |         for edge in (&self.state_network).edges(self.state) {
   |                     ^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:5...
  --> src/main.rs:28:5
   |
28 | /     pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
29 | |         for edge in (&self.state_network).edges(self.state) {
30 | |             if *edge.weight() == input {
31 | |                 self.state = edge.target();
...  |
38 | |         return Option::None;
39 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:29:21
   |
29 |         for edge in (&self.state_network).edges(self.state) {
   |                     ^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
  --> src/main.rs:15:6
   |
15 | impl<'a, G> StateMachine<'a, G>
   |      ^^
   = note: ...so that the expression is assignable:
           expected <&G as petgraph::visit::GraphBase>::NodeId
              found <&'a G as petgraph::visit::GraphBase>::NodeId

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:32:30
   |
32 |                 return match (&self.state_network).node_weight(self.state) {
   |                              ^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:5...
  --> src/main.rs:28:5
   |
28 | /     pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
29 | |         for edge in (&self.state_network).edges(self.state) {
30 | |             if *edge.weight() == input {
31 | |                 self.state = edge.target();
...  |
38 | |         return Option::None;
39 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:32:30
   |
32 |                 return match (&self.state_network).node_weight(self.state) {
   |                              ^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
  --> src/main.rs:15:6
   |
15 | impl<'a, G> StateMachine<'a, G>
   |      ^^
   = note: ...so that the expression is assignable:
           expected <&G as petgraph::visit::GraphBase>::NodeId
              found <&'a G as petgraph::visit::GraphBase>::NodeId

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.
4

1 回答 1

1

我现在不熟悉petgraph它的概念。根据我在结构中存储引用的经验,几乎总是以完全重写结束,所以我的方法是这样的:

struct StateMachine<G, E, N>
where
  G: GraphBase<EdgeId = E, NodeId = N>,
  E: Copy + PartialEq,
  N: Copy + PartialEq,
{
  state_network: G,
  state: N,
}

impl<G, E, N, EW, NW> StateMachine<G, E, N>
where
  G: Data<NodeWeight = NW, EdgeWeight = EW>
    + NodeIndexable
    + GraphProp
    + DataMap
    + GraphBase<EdgeId = E, NodeId = N>,
  E: Copy + PartialEq,
  N: Copy + PartialEq,
  for<'a> &'a G: IntoNodeReferences
    + IntoEdgeReferences
    + IntoEdges
    + Data<NodeWeight = NW, EdgeWeight = EW>
    + GraphBase<EdgeId = E, NodeId = N>,
  EW: Eq + Copy,
  NW: Eq + Copy,
{
  pub fn next<'a, 'b: 'a>(&'a mut self, input: EW) -> Option<NW> {
    for edge in (&self.state_network).edges(self.state) {
      if *edge.weight() == input {
        self.state = edge.target();
        return match self.state_network.node_weight(self.state) {
          Option::Some(weight) => Some(*weight),
          Option::None => Option::None,
        };
      }
    }
    return Option::None;
  }

  pub fn new(
    network: G,
    start: NW,
  ) -> Option<StateMachine<G, <G as GraphBase>::EdgeId, <G as GraphBase>::NodeId>> {
    let mut found = Option::None;

    for nr in network.node_references() {
      if *(network.node_weight(nr.id())).unwrap() == start {
        found = Option::Some(nr.id());
      }
    }
    found.map(|id| StateMachine {
      state_network: network,
      state: id,
    })
  }
}

EdgeIdNodeId获取泛型参数 ( E, N),因为这些参数在 , 的实现中被重用StateMachineNodeWeight并且EdgeWeight还获取泛型 ( NW, EW) 但仅加入和的关联&Graph类型Graph

于 2019-12-28T16:16:49.593 回答