【问题标题】:Iterate over struct Hashmap and add value to another portion of self遍历 struct Hashmap 并将值添加到 self 的另一部分
【发布时间】:2020-07-05 21:43:49
【问题描述】:

目前我有一个类似于以下的结构:

struct foo {
    pending: HashMap<K, V>,
    loaded: Vec<V>,
}

我正在尝试编写一个函数,它将所有待处理的 hashmap 值加载到已加载中,同时如果它们不符合特定标准,则从待处理中删除任何值,这就是我现在所拥有的:

pub async fn load(&mut self) {
    let mut rm_vector = Vec::new();
    for (key, value) in self.pending.iter_mut() {
        self.add_to_loaded(value).await.unwrap_or_else( |err| {
            if err == Error::SomeError {
                rm_vector.push(key.clone())
            }
        })
    }
    
    for value in rm_vector {
        self.pending.remove(&value);
    }
}

我遇到的问题是,在调用第一个 for 循环和之后的 if 语句时,我遇到了第二个可变借用错误。我想知道是否有人对如何在不克隆整个哈希图的情况下解决此问题有任何建议。

【问题讨论】:

  • 您能否发布实际代码(相关部分)。您粘贴的代码很难按原样遵循。我看到您有 .await 调用,但函数本身不是 async 函数,也不是在 async 块中运行。您是否正在尝试为您的 Struct 实现 Future 特征?
  • 啊我忘了在函数声明中添加异步。基本上 add_to_loaded 将给定的值添加到加载中,如果不满足某个标准,则抛出 SomeError 并且不添加到加载中。我没有包含 add_to_loaded 因为该函数大约有 100 行,所以只包含函数调用更有意义。
  • add_to_loaded 有 &amp;mut self 参数吗?
  • @Kitsu 是的,它有 &mut self 和 value 作为参数
  • 我无法重现您的问题。您能否添加函数add_to_loaded、Error 类型以及最重要的是确切的错误消息?

标签: struct rust hashmap


【解决方案1】:

我使用以下简化代码来复制问题。

use std::collections::HashMap;

struct Foo {
    pending: HashMap<String, u32>,
    loaded: Vec<u32>,
}

impl Foo {
    fn add_to_loaded(&mut self, v: u32) {
        self.loaded.push(v);
    }
}

impl Foo {
    pub fn load(&mut self) {
        for _ in self.pending.iter_mut() {
            self.add_to_loaded(30);
        }
    }
}

我认为原因是 iter_mut() 和 add_to_loaded(&mut) 都试图可变借用 self。

我可以想出两种方法来解决这个问题。

选项 A:

将加载的字段声明为 RefCell。有了它, add_to_loaded 的第一个参数可以声明为 self 的不可变引用,并使用 iter() 而不是 iter_mut() 来迭代 HashMap。 for 语句中不会有可变借用。在 add_to_loaded 中,使用 borrow_mut() 获取可变引用来修改加载的字段。

use std::collections::HashMap;
use std::cell::RefCell;

struct Foo {
    pending: HashMap<String, u32>,
    loaded: RefCell<Vec<u32>>,
}

impl Foo {
    fn add_to_loaded(&self, v: u32) {
        self.loaded.borrow_mut().push(v);
    }
}
impl Foo {
    pub fn load(&mut self) {
        for _ in self.pending.iter() {
            self.add_to_loaded(30);
        }
    }
}

选项 B: 将两个字段和两个方法拆分成两个结构体。

use std::collections::HashMap;

struct Foo {
    pending: HashMap<String, u32>,
}

struct Foo2 {
    loaded: Vec<u32>,
}

impl Foo {
    pub fn load(&mut self, f: &mut Foo2) {
        for _ in self.pending.iter() {
            f.add_to_loaded(30);
        }
    }
}

impl Foo2 {
    fn add_to_loaded(&mut self, v: u32) {
        self.loaded.push(v);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多