Loops 我如何变异我正在循环的结构?
这个问题的动机是 我正在使用Dijkstra的方法实现一个基本的寻路算法。它使用Loops 我如何变异我正在循环的结构?,loops,data-structures,rust,graph-algorithm,borrow-checker,Loops,Data Structures,Rust,Graph Algorithm,Borrow Checker,这个问题的动机是 我正在使用Dijkstra的方法实现一个基本的寻路算法。它使用boundaryHashMap和finishedHashMap来保存与寻路相关的节点信息。在一个特定的循环中,我在boundary中找到值最高的节点,删除节点,将节点添加到finished,并在boundary中添加/更新节点的邻居信息 试图在其上循环时变异边界,这让Rust的借阅检查器很不舒服,但循环的逻辑对我来说似乎是合理的。我如何重写它,使编译器分享我的信心?(或者修复我丢失的错误,如果这是问题的话。) 代码:
boundary
HashMap和finished
HashMap来保存与寻路相关的节点信息。在一个特定的循环中,我在boundary
中找到值最高的节点,删除节点,将节点添加到finished
,并在boundary
中添加/更新节点的邻居信息
试图在其上循环时变异边界
,这让Rust的借阅检查器很不舒服,但循环的逻辑对我来说似乎是合理的。我如何重写它,使编译器分享我的信心?(或者修复我丢失的错误,如果这是问题的话。)
代码:
使用std::io;
使用std::collections::{HashSet,HashMap};
使用std::cmp::Ordering;
使用std::cell::RefCell;
结构节点信息{
nbrs:HashSet,
gwlinks:i32,
}
#[推导(PartialEq,PartialOrd)]
结构PFInfo{
平均值:f32,
cum:i32,
地区:i32,
上:期权,
}
PFInfo{}的impl Eq
PFInfo请求{
fn cmp(&self,其他:&PFInfo)->订购{
匹配自身。部分_cmp(其他){
一些(ord)=>ord,
无=>排序::相等
}
}
}
类型图=HashMap;
类型PFGraph=HashMap;
//查找每行驶距离通过最多网关链接的路径,
//从给定节点开始。这是为了模拟
//“代理”,它遍历上述谜题中的图形。
fn生成路径(si:&i32,图形:&graph)->Vec{
设n=graph.len();
设mut boundary=PFGraph::具有_容量(n);
让mut finished=PFGraph::具有_容量(n);
boundary.insert(si.clone(),
PFInfo{
平均值:0。,
cum:graph.get(&si).unwrap().borrow().gwlinks,
地区:0,,
prev:None});
//继续抓取对应于最高值的键,直到找到“boundary”
//空的
而让Some((currid,)))=boundary.iter().max_by_key(|x | x.1){
//将节点从“边界”移动到“完成”`
让val=boundary.remove(&currid).unwrap();
finished.insert(currid.clone(),val);
//添加或更新未在“finished”中的所有相邻节点`
用于graph.get(&currid).unwrap()中的nbrid
.借用
.nbrs.iter()
.filter(|x |!已完成。包含_键(x)){
让currval=finished.get(&currid).unwrap();
让prev=Some(currid.clone());
设dist=currval.dist+1;
让cum=currval.cum+graph.get(nbrid.unwrap().borrow().gwlinks;
设平均值=立方米为f32/距离为f32;
边界.插入(
nbrid.clone(),
PFInfo{
平均值:平均值,
嗯:嗯,,
地区:地区,
prev:prev,
}
);
}
}
让mut path=Vec::new();
让mut currid=finished.iter().max_by_key(|x | x.1)。unwrap().0.clone();
push(currid.clone());
而让一些(previd)=完成。获取(&currid)。展开().prev{
push(previd.clone());
currid=previd.clone();
}
path.reverse();
路径
}
宏规则!解析输入{
($x:expr,$t:ident)=>($x.trim().parse::().unwrap())
}
#[测试]
fn测试_生成_路径(){
让mut inputs=“8 13 2
6 2
7 3
6 3
5 3
3 4
7 1
2 0
0 1
0 3
1 3
2 3
7 4
6 5
4.
5“。行();
让header=inputs.next().unwrap().split_whitespace().collect::();
设n=parse_input!(header[0],i32);//级别中的节点总数,包括网关
让l=parse_input!(header[1],i32);//链接数
让e=parse_input!(header[2],i32);//出口网关的数量
设mut-graph=graph::具有_容量(n为usize);
对于0..n中的节点{
insert(node,RefCell::new(NodeInfo{nbrs:HashSet::new(),gwlinks:0}));
}
设图=图;
对于0..l中的u,使用{
让link=inputs.next().unwrap();
让节点=link.split(“”).collect::();
让n1=parse_input!(节点[0],i32);//n1和N2定义这些节点之间的链接
设n2=parse_input!(节点[1],i32);
graph.get(&n1).unwrap().borrow_mut().nbrs.insert(n2);
graph.get(&n2).unwrap().borrow_mut().nbrs.insert(n1);
}
让mut gateways=HashSet::new();
对于0..e中的u作为usize{
让ei=parse_input!(inputs.next().unwrap(),i32);//网关节点的索引
网关。插入(ei);
}
让网关=网关;
用于网关中的gwid(&G){
用于&graph.get(gwid.unwrap().borrow().nbrs中的gwnbr{
(&graph).get(&gwnbr).unwrap().borrow_mut().gwlinks+=1;
}
}
断言_eq!(生成_路径(&0,&graph),vec![0,3]);
}
错误:
rustc 1.18.0(03fc9d622 2017-06-06)
错误[E0502]:无法将“boundary”借用为可变的,因为它也是借用为不可变的
--> :53:19
|
50 |而让一些((currid,|))=boundary.iter().max|u by|u key(| x | x.1){
|-----此处发生不可变借用
...
53 |让val=boundary.remove(&currid).unwrap();
|^^^^^^^^^^此处发生可变借用
...
76 | }
|-不可变的借阅到此结束
错误[E0502]:无法将“boundary”借用为可变的,因为它也是借用为不可变的
--> :66:13
|
50 |而让一些((currid,|))=boundary.iter().max|u by|u key(| x | x.1){
|-----此处发生不可变借用
...
66 | boundary.insert(
|^^^^^^^^^^此处发生可变借用
...
76 | }
|-不可变的借阅到此结束
错误:由于之前的两个错误而中止
我找到了一个解决我的问题的方法,它在某种程度上是可以推广的,这正是我所希望的
use std::io;
use std::collections::{HashSet, HashMap};
use std::cmp::Ordering;
use std::cell::RefCell;
struct NodeInfo {
nbrs: HashSet<i32>,
gwlinks: i32,
}
#[derive(PartialEq,PartialOrd)]
struct PFInfo {
avg: f32,
cum: i32,
dist: i32,
prev: Option<i32>,
}
impl Eq for PFInfo {}
impl Ord for PFInfo {
fn cmp(&self, other: &PFInfo) -> Ordering {
match self.partial_cmp(other) {
Some(ord) => ord,
None => Ordering::Equal
}
}
}
type Graph = HashMap<i32, RefCell<NodeInfo>>;
type PFGraph = HashMap<i32, PFInfo>;
// Find the path that passes the most gateway links per distance traveled,
// starting at a given node. This is meant to simulate the behavior of an
// "agent" which traverses the graph in the puzzle mentioned above.
fn generate_path(si: &i32, graph: &Graph) -> Vec<i32> {
let n = graph.len();
let mut boundary = PFGraph::with_capacity(n);
let mut finished = PFGraph::with_capacity(n);
boundary.insert( si.clone(),
PFInfo {
avg: 0.,
cum: graph.get(&si).unwrap().borrow().gwlinks,
dist: 0,
prev: None } );
// Keep grabbing the key corresponding the highest value until `boundary` is
// empty
while let Some( (currid, _) ) = boundary.iter().max_by_key(|x| x.1) {
// Move the node from `boundary` to `finished`
let val = boundary.remove(&currid).unwrap();
finished.insert(currid.clone(), val);
// Add or update all adjacent nodes that are not in `finished`
for nbrid in graph.get(&currid).unwrap()
.borrow()
.nbrs.iter()
.filter(|x| !finished.contains_key(x)) {
let currval = finished.get(&currid).unwrap();
let prev = Some(currid.clone());
let dist = currval.dist + 1;
let cum = currval.cum + graph.get(nbrid).unwrap().borrow().gwlinks;
let avg = cum as f32 / dist as f32;
boundary.insert(
nbrid.clone(),
PFInfo {
avg: avg,
cum: cum,
dist: dist,
prev: prev,
}
);
}
}
let mut path = Vec::new();
let mut currid = finished.iter().max_by_key(|x| x.1).unwrap().0.clone();
path.push(currid.clone());
while let Some(previd) = finished.get(&currid).unwrap().prev {
path.push(previd.clone());
currid = previd.clone();
}
path.reverse();
path
}
macro_rules! parse_input {
($x:expr, $t:ident) => ($x.trim().parse::<$t>().unwrap())
}
#[test]
fn test_generate_path() {
let mut inputs = "8 13 2
6 2
7 3
6 3
5 3
3 4
7 1
2 0
0 1
0 3
1 3
2 3
7 4
6 5
4
5".lines();
let header = inputs.next().unwrap().split_whitespace().collect::<Vec<_>>();
let n = parse_input!(header[0], i32); // the total number of nodes in the level, including the gateways
let l = parse_input!(header[1], i32); // the number of links
let e = parse_input!(header[2], i32); // the number of exit gateways
let mut graph = Graph::with_capacity(n as usize);
for node in 0..n {
graph.insert(node, RefCell::new(NodeInfo{ nbrs: HashSet::new(), gwlinks: 0 }));
}
let graph = graph;
for _ in 0..l as usize {
let link = inputs.next().unwrap();
let nodes = link.split(" ").collect::<Vec<_>>();
let n1 = parse_input!(nodes[0], i32); // N1 and N2 defines a link between these nodes
let n2 = parse_input!(nodes[1], i32);
graph.get(&n1).unwrap().borrow_mut().nbrs.insert(n2);
graph.get(&n2).unwrap().borrow_mut().nbrs.insert(n1);
}
let mut gateways = HashSet::new();
for _ in 0..e as usize {
let ei = parse_input!(inputs.next().unwrap(), i32); // the index of a gateway node
gateways.insert(ei);
}
let gateways = gateways;
for gwid in &gateways {
for gwnbr in &graph.get(gwid).unwrap().borrow().nbrs {
(&graph).get(&gwnbr).unwrap().borrow_mut().gwlinks += 1;
}
}
assert_eq!(generate_path(&0, &graph), vec![0, 3]);
}
while let Some( (currid, _) ) = boundary.iter().max_by_key(|x| x.1).clone() {
// ^---where borrow begins ^---where borrow could end
// Move the node from `boundary` to `finished`
let val = boundary.remove(&currid).unwrap();
finished.insert(currid.clone(), val);
...
} // <--- where borrow does end
while !boundary.is_empty() {
let currid = boundary.iter().max_by_key(|x| x.1).unwrap().0.clone();
// ^---where borrow begins ^---where borrow ends
// Move the node from `boundary` to `finished`
let val = boundary.remove(&currid).unwrap();
finished.insert(currid.clone(), val);
...
}