【问题标题】:Storing an iterator for a HashMap in a struct在结构中存储 HashMap 的迭代器
【发布时间】:2021-02-24 15:41:38
【问题描述】:

编辑

从建议的解决方案看来,我想要实现的目标似乎是不可能的/不是正确的方法,因此 - 我将在这里解释最终目标:

我正在使用 serde 从 YAML 文件中解析 Foo 的值,我想让用户一次从 yaml 中获取其中一个存储值,这就是为什么我想在我的结构中存储一个迭代器


我有两个类似于以下的结构:

struct Bar {
    name: String,
    id: u32
}

struct Foo {
    my_map: HashMap<String, Bar>
}

在我的Foo 结构中,我希望将一个迭代器存储到我的 HashMap 中,以便用户可以根据需要从我的映射中借用值。 从理论上讲,完整的 Foo 类看起来像:

struct Foo {
    my_map: HashMap<String, Bar>,
    my_map_iter: HashMap<String, Bar>::iterator
}

impl Foo {
    fn get_pair(&self) -> Option<(String, Bar)> {
        // impl...
    }
}

但无论我尝试什么,我似乎都无法完成并创建这样一个变量(各种编译错误,似乎我只是试图做错)。

如果有人能指出实现这一目标的正确方法,以及是否有更好的方法来实现我正在尝试做的事情,我会很高兴 - 我想知道这一点。

谢谢!

【问题讨论】:

  • 我也不确定它本身是否有意义:“用户可以按需从我的地图中借用值”一旦迭代器用完会发生什么?
  • @Masklinn 我最初的意图是创建一个新的迭代器并重新开始 - 我使用 serde 解析来自 YAML 的值,并希望让类的用户按需使用这些值
  • 我撤回了我的重复投票,因为您现在正在寻找特定的解决方法。但是,您能否阐明所需的模式?为什么你的Foo 类不能提供一个迭代器供用户在闲暇时使用?
  • @kmdreko 在我的实际用例中,Bar 是一个服务器配置,稍后我需要在代码中的其他位置使用它来尝试连接到该服务器。我的 YAML 文件包含许多这样的设置,有时我想使用一个新设置。我的 Foo 结构是我解析 YAML 并将其存储以供以后使用的地方。 YAML 不是太大,所以我也可以将它全部保存在内存中。

标签: rust iterator


【解决方案1】:

我正在使用 serde 从 YAML 文件中解析 Foo 的值

当您解析它们时,您应该将值放在Vec 而不是HashMap

我想你的值也有名字,这就是为什么你认为HashMap 会很好。您可以像这样存储它们:

let parsed = vec![]

for _ in 0..n_to_parse {
    // first item of the tuple is the name second is the value
    let key_value = ("Get from", "serde");
    parsed.push(key_value);
}

然后,一旦你像这样存储它,通过跟踪当前索引就可以很容易地从中获取对:

struct ParsedHolder {
    parsed: Vec<(String, String)>,
    current_idx: usize,
}

impl ParsedHolder {
    fn new(parsed: Vec<(String, String)>) -> Self {
        ParsedHolder {
            parsed,
            current_idx: 0,
        }
    }

    fn get_pair(&mut self) -> Option<&(String, String)> {
        if let Some(pair) = self.parsed.get(self.current_idx) {
            self.current_idx += 1;
            Some(pair)

        } else {
            self.current_idx = 0;
            None
        }
    }
}

现在可以通过使用VecDeque 进一步改进这将允许您有效地取出已解析的第一个元素。这将使不使用克隆变得容易。但是这样一来,您将只能遍历一次所有解析的值,我认为这实际上是您在用例中想要的。

但我会让你实现VecDeque?

【讨论】:

  • 如果将其直接收集到向量中很痛苦,您可以使用hashmap::into_iter()::collect::Vec&lt;_, _&gt;()
  • 再次感谢您提供另一个解决方案!我使用 HashMap 的原因是因为可以更新此 YAML(我还在几分钟内对该 YAML 进行一次采样),然后我可能需要更新其中一个字段,我可以在 O(1) 中访问该字段因为我会知道什么 ID 发生了变化。但是由于 YAML 不应该那么大,并且因为 HashMap 让我很难在需要时实际使用解析的值,所以切换到向量确实可能是一个更好的主意,然后我将重新解析我的 YAML。
  • 当您仍在从中获取配对时,是否会发生这样的值更新?
  • @OrY 如果 YAML 可以更新,则无论如何都必须解析整个内容,因此将整个内容换掉而不是尝试查看更改的内容可能会更少工作交换那些。
  • @kmdreko你确实是对的,所以我会尝试将YAML解析更改为向量而不是HashMap
【解决方案2】:

这很难的原因是,除非我们确保 HashMap 在迭代时没有发生突变,否则我们可能会遇到一些麻烦。要确保 HashMap 在迭代器存在之前是不可变的:

use std::collections::HashMap;
use std::collections::hash_map::Iter;

struct Foo<'a> {
    my_map: &'a HashMap<u8, u8>,
    iterator: Iter<'a, u8, u8>,
}

fn main() {
    let my_map = HashMap::new();
    let iterator = my_map.iter();

    let f = Foo {
        my_map: &my_map,
        iterator: iterator,
    };
}

如果您可以确定或知道 HashMap 不会有新键或从中删除键(使用现有键编辑值很好),那么您可以这样做:

struct Foo {
    my_map: HashMap<String, String>,
    current_idx: usize,
}

impl Foo {
    fn new(my_map: HashMap<String, String>) -> Self {
        Foo {
            my_map,
            current_idx: 0,
        }
    }

    fn get_pair(&mut self) -> Option<(&String, &String)> {
        if let Some(pair) = self.my_map.iter().skip(self.current_idx).next() {
            self.current_idx += 1;
            Some(pair)

        } else {
            self.current_idx = 0;
            None
        }
    }

    fn get_pair_cloned(&mut self) -> Option<(String, String)> {
        if let Some(pair) = self.my_map.iter().skip(self.current_idx).next() {
            self.current_idx += 1;
            Some((pair.0.clone(), pair.1.clone()))

        } else {
            self.current_idx = 0;
            None
        }
    }
}

虽然这相当低效,因为我们每次都需要遍历键以找到下一个键。

【讨论】:

  • 首先谢谢您!虽然它似乎可以工作并解决我的解决方案,但我希望提高效率并且我担心稍后我可能想要修改 HashMap 中的一个值,我想知道是否有更好的方法为我的结构实现一个方法,该方法在请求时从我的 HashMap 中返回一个键值对。 (理想情况下,我会使用 IndexMap,但我很难将 YAML 解析到其中,因为它不像 HashMap 那样与 serde 一起工作)。
猜你喜欢
  • 2022-06-30
  • 2015-01-25
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 1970-01-01
相关资源
最近更新 更多