如何遍历 Hashmap,打印键/值并删除 Rust 中的值? [英] How to iterate through a Hashmap, print the key/value and remove the value in Rust?

查看:37
本文介绍了如何遍历 Hashmap,打印键/值并删除 Rust 中的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这在任何语言中都应该是一项微不足道的任务.这在 Rust 中不起作用.

使用 std::collections::HashMap;fn do_it(map: &mut HashMap) {for (key, value) in map {println!("{}/{}", key, value);map.remove(key);}}fn main() {}

这是编译器错误:

error[E0382]:使用移动值:`*map`-->src/main.rs:6:9|4 |for (key, value) in map {|--- 值移到这里5 |println!("{}/{}", key, value);6 |map.remove(key);|^^^ 此处使用移动后的值|= 注意:发生移动是因为 `map` 的类型为 `&mut std::collections::HashMap<std::string::String, std::string::String>`,它没有实现 `Copy` trait

为什么要移动引用?从文档中,我不认为移动/借用适用于参考.

解决方案

不允许这样做的原因至少有两个:

  1. 您需要有两个对 map 的并发可变引用——一个由 for 循环中使用的迭代器保存,另一个保存在变量 map 调用map.remove.

  2. 在尝试改变映射时,您引用了映射中 中的键和值.如果您被允许以任何方式修改映射,这些引用可能会失效,从而为内存不安全打开大门.

Rust 的核心原则是别名异或可变性.您可以有多个对一个值的不可变引用,也可以有一个对它的可变引用.

<块引用>

我认为搬家/借用不适用于参考文献.

每种类型都遵循 Rust 的移动规则和可变别名.请告诉我们文档的哪一部分不是这样,以便我们解决这个问题.

<块引用>

为什么要移动引用?

这是由两部分组合而成的:

  1. 你只能有一个可变引用,所以可变引用不实现 复制 trait
  2. for 循环 取值按值迭代

当你在 map {} 中调用 for (k, v) 时,map 的所有权被转移到 for 循环,现在消失了.


我会执行地图的不可变借用 (&*map) 并对其进行迭代.最后,我会清除整个事情:

fn do_it(map: &mut HashMap) {for (key, value) in &*map {println!("{}/{}", key, value);}地图.清除();}

<块引用>

使用以字母A"开头的键删除每个值

我会使用 HashMap::保留:

fn do_it(map: &mut HashMap) {map.retain(|key, value| {println!("{}/{}", key, value);!key.starts_with(a")})}

这保证了 keyvalue 在实际修改地图时不再存在,因此它们本来应该拥有的任何借用现在都消失了.

This should be a trivial task in any language. This isn't working in Rust.

use std::collections::HashMap;

fn do_it(map: &mut HashMap<String, String>) {
    for (key, value) in map {
        println!("{} / {}", key, value);
        map.remove(key);
    }
}

fn main() {}

Here's the compiler error:

error[E0382]: use of moved value: `*map`
 --> src/main.rs:6:9
  |
4 |     for (key, value) in map {
  |                         --- value moved here
5 |         println!("{} / {}", key, value);
6 |         map.remove(key);
  |         ^^^ value used here after move
  |
  = note: move occurs because `map` has type `&mut std::collections::HashMap<std::string::String, std::string::String>`, which does not implement the `Copy` trait

Why it is trying to move a reference? From the documentation, I didn't think moving/borrowing applied to references.

解决方案

There are at least two reasons why this is disallowed:

  1. You would need to have two concurrent mutable references to map — one held by the iterator used in the for loop and one in the variable map to call map.remove.

  2. You have references to the key and the value within the map when trying to mutate the map. If you were allowed to modify the map in any way, these references could be invalidated, opening the door for memory unsafety.

A core Rust principle is Aliasing XOR Mutability. You can have multiple immutable references to a value or you can have a single mutable reference to it.

I didn't think moving/borrowing applied to references.

Every type is subject to Rust's rules of moving as well as mutable aliasing. Please let us know what part of the documentation says it isn't so we can address that.

Why it is trying to move a reference?

This is combined of two parts:

  1. You can only have a single mutable reference, so mutable references don't implement the Copy trait
  2. for loops take the value to iterate over by value

When you call for (k, v) in map {}, the ownership of map is transferred to the for loop and is now gone.


I'd perform an immutable borrow of the map (&*map) and iterate over that. At the end, I'd clear the whole thing:

fn do_it(map: &mut HashMap<String, String>) {
    for (key, value) in &*map {
        println!("{} / {}", key, value);
    }
    map.clear();
}

remove every value with a key that starts with the letter "A"

I'd use HashMap::retain:

fn do_it(map: &mut HashMap<String, String>) {
    map.retain(|key, value| {
        println!("{} / {}", key, value);

        !key.starts_with("a")
    })
}

This guarantees that key and value no longer exist when the map is actually modified, thus any borrow that they would have had is now gone.

这篇关于如何遍历 Hashmap,打印键/值并删除 Rust 中的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆