如何将两个变量之间的双向关系存储为第三个变量?

时间:2017-04-18 10:57:40

标签: rust

我有一系列国家,我希望产生这些国家之间的关系,因此国家A和国家B之间的关系总是与国家B和国家A之间的关系相同。

例如,日本和厄瓜多尔的关系值为15.我希望能够同时运行get_relationship("Japan", "Ecuador");get_relationship("Ecuador", "Japan");并始终获得15。理想情况下,我不想两次存储此值,因为我不想让它保持同步。

以下是我目前的实验代码。请注意,由于无关原因,我将国家/地区存储为HashMap (name as String, Nation as struct),主要是因为我可以仅通过名称提取所需的Nation对象。

extern crate rand;

use std::collections::HashMap;
use rand::Rng;

struct Nation;

pub struct NationManager {
    nations: HashMap<String, Nation>, // The string is the nation's name
    rels: HashMap<String, HashMap<String, i8>>, // Again, both Strings are names
}

impl NationManager {
    fn generate_relationships(&mut self) {
        let mut random_rel: i8 = rand::thread_rng().gen_range(1, 101);
        for (source, _) in &self.nations {
            for (target, _) in &self.nations {
                if source > target {
                    self.rels
                        .get(source)
                        .expect("ERROR")
                        .insert(target.clone(), random_rel);
                } else if source < target {
                    self.rels
                        .get(target)
                        .expect("ERROR")
                        .insert(source.clone(), random_rel);
                } else {
                    continue;
                }
            }
        }
    }
}

fn main() {}

我不认为这是达到预期结果的最佳方式,而且目前还没有编译;实际上可以像这样嵌套两个for循环吗?

error: cannot borrow immutable borrowed content as mutable
  --> src/main.rs:19:21
   |
19 |                       self.rels
   |  _____________________^ starting here...
20 | |                         .get(source)
21 | |                         .expect("ERROR")
   | |________________________________________^ ...ending here: cannot borrow as mutable

error: cannot borrow immutable borrowed content as mutable
  --> src/main.rs:24:21
   |
24 |                       self.rels
   |  _____________________^ starting here...
25 | |                         .get(target)
26 | |                         .expect("ERROR")
   | |________________________________________^ ...ending here: cannot borrow as mutable

2 个答案:

答案 0 :(得分:5)

首先要做的事情是:您遇到的问题是get会返回一个不可变引用,并且您会尝试insert。您可能希望使用get_mut获取可执行insert的可变引用。

但我建议改变设计:

  1. 存储地图名称 - &gt; ID,
  2. 使用ID作为其他地图中的关键字。
  3. 这种方案的主要优点是数字ID比字符串便宜/高效。

    pub struct NationManager {
        last_id: u32,
        name_to_id: HashMap<String, u32>,
        relationships: HashMap<(u32, u32), i8>, // (smaller ID, larger ID) -> score
    }
    

    查看两个国家/地区之间的关系将涉及了解他们的ID(name_to_id中的两个查找),然后查找关系分数。

    relationships的扁平化将极大地 简化了你的生成步骤:

    impl NationManager {
        fn generate_relationships(&mut self) {
            let random_rel: i8 = rand::thread_rng().gen_range(1, 101);
            for source in 0..self.last_id {
                for target in (source + 1)..self.last_id {
                    self.relationships.insert((source, target), random_rel);
                }
            }
        }
    }
    

    注意:实际上,域分析可以让我们使用更小的ID;你不应该超过65,535个国家,所以u16肯定是足够的,并且u8(255个国家)也足够(有193个国家)在联合国登记。

答案 1 :(得分:1)

问题是你使用的是错误的方法。 HashMap::get不允许您改变结果:

fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> 
    where K: Borrow<Q>,
          Q: Hash + Eq,

您想要get_mut

fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> 
    where K: Borrow<Q>,
          Q: Hash + Eq,