rust 尝试从Map中过滤元素时会出现“cannot move”,因为字段为String

cygmwpex  于 2023-04-06  发布在  其他
关注(0)|答案(1)|浏览(299)

我有一个HashMap<u8, Item>,其中Item是一个结构体,包含其他字段,一个String:

#[derive(Debug, Clone)]
pub struct Item {
    name: String,
    kind: u8,
    accepted_values: Vec<u8>
}

我正在尝试获取HashMap中包含accepted_values属性中特定值的项:

type ItemDatabase = HashMap<u8,Item>;
pub trait ItemDatabaseExtension {
    fn filter(&self, find_by: u8) -> ItemDatabase;
}

impl ItemDatabaseExtension for ItemDatabase {
    fn filter(&self, find_by: u8) -> ItemDatabase {
        let filtered_map = self
            .iter()
            .filter(|(_, &value)| {
                value.accepted_values.contains(&room_type)
            })
            .map(|(&key, &value)| {
                (key, value)
            })
            .collect();
        
        return filtered_map;
    }
}

我的想法是得到一个元素的副本。至少我没有修改它们的意图。
然而,编译器抱怨无法移动filter中的值,因为Item没有实现trait Copy。问题是Item包含String字段,并且不允许(只要我知道)结构实现Copy

error[E0507]: cannot move out of a shared reference
  --> item.rs:52:22
   |
52 |             .filter(|(_, &value)| {
   |                      ^^^^^-----^
   |                           |
   |                           data moved here
   |                           move occurs because `value` has type `item::Item`, which does not implement the `Copy` trait

我是Rust的新手,所以我不完全理解如何掌握可能面临的借用问题。我理解在rust文档中找到的简单示例,但当我在更“复杂”的场景中面对它们时就不理解了。
我尝试删除.filter(|(_,value)|.map(|(&key,value)|上的&,但这只会将错误移动到.collect()调用:

error[E0277]: a value of type `HashMap<u8, item::Item>` cannot be built from an iterator over elements of type `(u8, &item::Item)`
    --> item.rs:58:14
     |
58   |             .collect();
     |              ^^^^^^^ value of type `HashMap<u8, item::Item>` cannot be built from `std::iter::Iterator<Item=(u8, &item::Item)>`

基本上我不知道我在做什么。

5lhxktic

5lhxktic1#

问题是,当引用的类型实现了Copy时,你只能用&v模式来解构引用,因为你实现了Clone,你可以使用它来代替:

impl ItemDatabaseExtension for ItemDatabase {
    fn filter(&self, room_type: u8) -> Self {
        self.iter()
            .filter_map(|(&key, value)| {
                value
                    .accepted_values
                    .contains(&room_type)
                    .then(|| (key, value.clone()))
            })
            .collect();
    }
}

此外,您还可以将filtermap合并为一个filter_map,就像我上面所做的那样。Playground

相关问题