为遍历其HashMap属性的结构体实现IntoIterator。

7

我有一个结构体,其中包含一个类型为HashMap的属性。我想为这个结构体实现IntoIterator特质,以便可以迭代它的HashMap属性。但问题是我遇到了生命周期方面的麻烦:

pub struct ProcessList {
    map: HashMap<ProcessPtr, usize>,
}

impl ProcessList {
    pub fn new() -> ProcessList {
        ProcessList {
            map: HashMap::new(),
        }
    }

    pub fn add(self, process: ProcessPtr, nb: usize) {
        match self.map.contain_key(process) {
            true => self.map[process] += nb,
            false => self.map.insert(process, nb),
        };
    }
}

impl<'a> IntoIterator for ProcessList {
    type Item = (&'a ProcessPtr, &'a usize);
    type IntoIter = Iter<'a, ProcessPtr, usize>;

    fn into_iter(self) -> Self::IntoIter {
        self.map.into_iter()
    }
}

1
请在下次提问时在Rust Playground上提供可工作的最小可复现代码,这将为回答你问题的人节省很多时间。 - Matthieu M.
2个回答

4

查看在stdlib中为HashMap实现的IntoIterator:source

如果您要为ProcessList实现IntoIterator,则根本不需要引用和生命周期:

use std::collections::HashMap;
use std::collections::hash_map::IntoIter;

#[derive(Eq,PartialEq,Hash)]
pub struct ProcessPtr;

pub struct ProcessList {
    map: HashMap<ProcessPtr, usize>,
}

impl ProcessList {
    pub fn new() -> ProcessList {
        ProcessList {
            map: HashMap::new(),
        }
    }

    pub fn add(self, process: ProcessPtr, nb: usize) {
    /* Bunch of errors here
        match self.map.contains_key(process) {
            true => self.map[process] += nb,
            false => self.map.insert(process, nb),
        };
    */
    }
}

impl IntoIterator for ProcessList {
    type Item = (ProcessPtr, usize);
    type IntoIter = IntoIter<ProcessPtr, usize>;

    fn into_iter(self) -> Self::IntoIter {
        self.map.into_iter()
    }
}

fn main(){
}

同时,你的代码在 add 函数中存在一些错误。


警告:根据HashMap::into_iter文档,“调用此函数后,映射将不能再使用”。在这种情况下,似乎您必须处理生命周期。 - reubenjohn

1

基于借用和拥有的迭代器

@aSpex 的答案是一个拥有的迭代器实现,这意味着在迭代过程中从地图中删除(或消耗)元素,这似乎不是 OP 的要求(有关更多信息,请参见我的评论)。Aloso's 博客文章 是这个主题的好读物。

通过正确实现下面的生命周期,我们可以避免消耗地图:

impl<'a> IntoIterator for &'a ProcessList {
    type Item = (&'a ProcessPtr, &'a usize);
    type IntoIter = hash_map::Iter<'a, ProcessPtr, usize>;

    fn into_iter(self) -> hash_map::Iter<'a, ProcessPtr, usize> {
        self.map.iter()
    }
}

使用for循环的效果如下所示。请注意,我们现在可以使用&来借用&my_process_list,以防止消耗。

fn main() {
    // --snip--

// These are now; Notice the
// &references  ; borrow
//        /\      | 
//       v  v     v
    for (k, v) in &my_process_list {
        println!("({k}, {v})");
    }
    // Yay! It still has my data:
    assert!(original_count == my_process_list.into_iter().count());
    assert!(original_count == my_process_list.into_iter().count());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接