如何在petgraph的GraphMap中移除指定节点的所有出边?编译报错求助
解决petgraph GraphMap中移除指定节点所有出边的编译错误
需求与尝试代码
需要移除有向GraphMap中指定节点的所有出边,尝试的代码如下:
use petgraph::{graphmap::GraphMap, visit::EdgeRef, Directed, Direction}; fn main() { let mut g = GraphMap::<MyNode, u32, Directed>::new(); let node1 = MyNode { value1: 1, value2: 1 }; let node2 = MyNode { value1: 2, value2: 2 }; g.add_node(node1); g.add_node(node2); g.add_edge(node1, node2, 1); g.edges_directed(node1, Direction::Outgoing).for_each(|edge| { g.remove_edge(edge.source(), edge.target()); }); println!("{:?}", g); } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MyNode { pub value1: u32, pub value2: u32, }
编译错误
代码无法通过编译,报错信息如下:
Compiling playground v0.0.1 (/playground) error[E0502]: cannot borrow `g` as mutable because it is also borrowed as immutable --> src/main.rs:11:59 | 11 | g.edges_directed(node1, Direction::Outgoing).for_each(|edge| { | - -------- ^^^^^^ mutable borrow occurs here | | | | immutable borrow occurs here immutable borrow later used by call 12 | g.remove_edge(edge.source(), edge.target()); | - second borrow occurs due to use of `g` in closure
问题原因
edges_directed方法返回的迭代器持有GraphMap的不可变引用,而闭包中调用remove_edge需要获取GraphMap的可变引用。Rust的借用规则禁止同一时间对同一值同时存在不可变和可变引用,因此编译失败。
解决方案
先将所有需要移除的边的(源节点,目标节点)对收集到一个临时向量中,待迭代器的不可变借用结束后,再遍历这个向量移除边:
use petgraph::{graphmap::GraphMap, visit::EdgeRef, Directed, Direction}; fn main() { let mut g = GraphMap::<MyNode, u32, Directed>::new(); let node1 = MyNode { value1: 1, value2: 1 }; let node2 = MyNode { value1: 2, value2: 2 }; g.add_node(node1); g.add_node(node2); g.add_edge(node1, node2, 1); // 收集所有待移除的边的节点对 let edges_to_remove: Vec<_> = g.edges_directed(node1, Direction::Outgoing) .map(|edge| (edge.source(), edge.target())) .collect(); // 遍历移除边 for (source, target) in edges_to_remove { g.remove_edge(source, target); } println!("{:?}", g); } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MyNode { pub value1: u32, pub value2: u32, }
这种方式先通过不可变借用完成边信息的收集,此时迭代器的借用已经释放,后续的可变借用修改GraphMap完全符合Rust的借用规则,代码可以正常编译运行。
内容的提问来源于stack exchange,提问作者Ron Slosberg
相关产品推荐
相关产品推荐

