简体   繁体   English

在结构中存储 HashMap 的迭代器

[英]Storing an iterator for a HashMap in a struct

Edit编辑

As it seemms from the suggested solution, What I'm trying to achieve seems impossible/Not the correct way, therefore - I'll explain the end goal here:从建议的解决方案看来,我试图实现的目标似乎是不可能的/不是正确的方法,因此 - 我将在这里解释最终目标:

I am parsing the values for Foo from a YAML file using serde, and I would like to let the user get one of those stored values from the yaml at a time, this is why I wanted to store an iterator in my struct我正在使用 serde 从 YAML 文件中解析 Foo 的值,我想让用户一次从 yaml 中获取其中一个存储值,这就是为什么我想在我的结构中存储一个迭代器


I have two struct similar to the following:我有两个类似于以下的结构:

struct Bar {
    name: String,
    id: u32
}

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

In my Foo struct, I wish to store an iterator to my HashMap, so a user can borrow values from my map on demand.在我的Foo结构中,我希望将一个迭代器存储到我的 HashMap 中,以便用户可以根据需要从我的 map 中借用值。 Theoretically, the full Foo class would look something like:从理论上讲,完整的 Foo class 看起来像:

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

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

But I can't seem to pull it off and create such a variable, no matter what I try (Various compilation errors which seems like I'm just trying to do that wrong).但无论我尝试什么,我似乎都无法将它拉下来并创建这样一个变量(各种编译错误,似乎我只是试图做错)。

I would be glad if someone can point me to the correct way to achieve that and if there is a better way to achieve what I'm trying to do - I would like to know that.如果有人能指出我实现这一目标的正确方法,并且如果有更好的方法来实现我正在尝试做的事情,我会很高兴 - 我想知道这一点。

Thank you!谢谢!

I am parsing the values for Foo from a YAML file using serde我正在使用 serde 从 YAML 文件中解析 Foo 的值

When you parse them you should put the values in a Vec instead of a HashMap .解析它们时,您应该将值放在Vec而不是HashMap中。

I imagine the values you have also have names which is why you thought a HashMap would be good.我想您的值也有名称,这就是为什么您认为HashMap会很好。 You could instead store them like so:您可以像这样存储它们:

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);
}

then once you stored it like so it will be easy to get the pairs from it by keeping track of the current index:然后,一旦您像这样存储它,就可以通过跟踪当前索引轻松地从中获取对:

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
        }
    }
}

Now this could be further improved upon by using VecDeque which will allow you to efficiently take out the first element of parsed.现在这可以通过使用VecDeque进一步改进,这将允许您有效地取出 parsed 的第一个元素。 Which will make it easy to not use clone.这将使不使用克隆变得容易。 But this way you will be only able to go through all the parsed values once which I think is actually what you want in your use case.但是这样一来,您将只能通过所有已解析的值 go 一次,我认为这实际上是您在用例中想要的。

But I'll let you implement VecDeque但我会让你实现VecDeque

The reason why this is a hard is that unless we make sure the HashMap isn't mutated while we iterate we could get into some trouble.这很难的原因是,除非我们确保HashMap在我们迭代时没有发生突变,否则我们可能会遇到一些麻烦。 To make sure the HashMap is immutable until the iterator lives:为了确保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,
    };
}

If you can make sure or know that the HashMap won't have new keys or keys removed from it (editing values with existing keys is fine) then you can do this:如果您可以确定或知道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
        }
    }
}

This is fairly inefficient though because we need to iterate though the keys to find the next key each time.但是这相当低效,因为我们每次都需要遍历键以找到下一个键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM