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

Rust 如何将两个变量之间的双向关系存储为第三个变量?,rust,Rust,我有一系列的国家,我想建立这些国家之间的关系,这样国家A和国家B之间的关系总是与国家B和国家A之间的关系相同 例如,日本和厄瓜多尔的关系值为15。我希望能够同时运行get_关系(“日本”、“厄瓜多尔”)和获取关系(“厄瓜多尔”、“日本”)并始终获得15。理想情况下,我不想将这个值存储两次,因为我不想费心让它保持同步 下面是我目前的实验代码。请注意,我将国家存储为的HashMap(名称为字符串,国家为结构),这是出于不相关的原因,主要是因为我可以单独按名称提取所需的国家对象 extern crat

我有一系列的国家,我想建立这些国家之间的关系,这样国家A和国家B之间的关系总是与国家B和国家A之间的关系相同

例如,日本和厄瓜多尔的关系值为15。我希望能够同时运行
get_关系(“日本”、“厄瓜多尔”)
获取关系(“厄瓜多尔”、“日本”)并始终获得
15
。理想情况下,我不想将这个值存储两次,因为我不想费心让它保持同步

下面是我目前的实验代码。请注意,我将国家存储为
HashMap
(名称为字符串,国家为结构)
,这是出于不相关的原因,主要是因为我可以单独按名称提取所需的
国家
对象

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() {}

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

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

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

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

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


但是,我建议修改设计:

  • 存储地图名称->ID
  • 在其他地图中使用ID作为键
  • 此方案的主要优点是数字ID比字符串便宜/高效

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

    注意:实际上,域分析也可以让我们使用更小的ID;你不需要超过65535个国家,所以u16肯定足够了,而且
    u8
    (255个国家)也足够了(联合国注册了193个国家)。

    第一件事:你的问题是
    get
    返回一个不可变的引用,然后尝试在其中插入
    。您可能希望使用
    get_mut
    获取一个可执行
    insert
    的可变引用


    但是,我建议修改设计:

  • 存储地图名称->ID
  • 在其他地图中使用ID作为键
  • 此方案的主要优点是数字ID比字符串便宜/高效

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

    注意:实际上,域分析也可以让我们使用更小的ID;你需要的国家不应该超过65535个,因此u16肯定足够了,而且
    u8(255个国家)也足够了(联合国注册了193个国家)。

    一个不相关的注释:与其使用
    .expect(“ERROR”)
    ,不如使用
    .unwrap()
    ,而不是
    ,这对眼睛更容易。
    expect()
    的要点是提供有意义的错误消息。编译器提供的实际错误消息是什么?“由于所有权问题而无法编译”不是很有用。@user4815162342我重申,“当前实验代码”@E_net4“不能以可变方式借用”,指向
    self.rels.get(target.expect(“ERROR”)
    。我希望有人能有更好的解决办法。我无法想象我是如何完成这项任务的。请编辑你的问题以包含更多内容。@Quintus:顺便问一下,随机生成不应该在循环中吗?似乎所有国家的关系得分都是相等的。一个不相关的注意事项:与其使用
    .expect(“ERROR”)
    ,不如使用
    .unwrap()
    ,这样看起来更容易。
    expect()
    的要点是提供有意义的错误消息。编译器提供的实际错误消息是什么?“由于所有权问题而无法编译”不是很有用。@user4815162342我重申,“当前实验代码”@E_net4“不能以可变方式借用”,指向
    self.rels.get(target.expect(“ERROR”)
    。我希望有人能有更好的解决办法。我无法想象我是如何完成这项任务的。请编辑你的问题以包含更多内容。@Quintus:顺便问一下,随机生成不应该在循环中吗?似乎所有国家在这方面的关系得分都是相等的。“你应该需要超过65535个国家”?:)这是一个非常聪明的解决方案,谢谢!使用数字肯定会让我更容易理解。因此,对于getter,我可以假设任意两个国家之间的关系存储在
    (低ID,高ID)
    元组中,对吗?另外,感谢您指出了
    get_mut
    方法-我仍然在用
    u8
    /
    u16
    /
    /
    u32
    -88字节来概括Rust.FWIW中的所有权。@Shepmaster:a
    Vec
    和a
    Vec
    也将具有相同的大小,但其堆分配的数组将具有不同的大小。这同样适用于
    HashMap
    (baring padding)。当然,由于缓冲区是内部的,所以检查起来有点困难,而且我不确定
    HashMap
    是否利用了较小的键。BLUS的OrderedMap将使用单独的
    Vec
    “您应该需要超过65535个国家”?:)这是一个非常聪明的解决方案,谢谢!使用数字肯定会让我更容易理解。因此,对于getter,我可以假设任意两个国家之间的关系存储在
    (低ID,高ID)
    元组中,对吗?另外,感谢您指出了
    get_mut
    方法-我仍然在用
    u8
    /
    u16
    /
    /
    u32
    -88字节来概括Rust.FWIW中的所有权。@Shepmaster:a
    Vec
    和a
    Vec
    也将具有相同的大小,但其堆分配的数组将具有不同的大小。这同样适用于
    HashMap
    (baring padding)。属于