为什么我需要取消引用 HashMap 的键两次?

Why do I need to dereference HashMap's key twice?

我才学 Rust 几天。我认为这两个代码示例是相同的,但编译器不同意。你能解释一下第二部分发生了什么吗?为什么我需要取消引用 key 两次,但 value 一次?

第一部分

use std::collections::HashMap;

let mut h = HashMap::new();   
h.insert(1, 1);
h.insert(2, 2);

let mut keys: Vec<i32> = Vec::new();
let mut values: Vec<i32> = Vec::new();

for (k, v) in &h {
    keys.push(**k);
    values.push(*v);
}

第二部分

fn main() {
    let mut v = vec![2, 3, 5, 1, 2, 3, 8, 6, 3, 1, 4, 6, 7];

    use std::collections::HashMap;

    let mut h = HashMap::new();

    for element in &v {
        let count = h.entry(element).or_insert(0);

        *count += 1;
    }

    let mut keys: Vec<i32> = Vec::new();
    let mut values: Vec<i32> = Vec::new();

    for (k, v) in &h {
        keys.push(**k);
        values.push(*v);
    }

    println!("{:?}", keys);
}

你只需要解引用一次

这是您的代码的 example

由于您没有指定 HashMap 的类型,编译器会推断出它。

let v = vec![1i32, 2, 3];
let mut h = HashMap::new();
for i in &v {
    h.insert(i, ());
}

这里h的类型是HashMap<&i32, ()>i的类型是&i32。为什么 i 的类型是 &i32?因为这就是 IntoIterator on &Vec 的实现方式。一般来说,当你迭代一个引用时,你会得到引用。

如果您想要 HashMap 键类型不是引用,您可以这样说。然后,当您尝试插入引用时,您会收到不同的错误消息。

let v = vec![1i32, 2, 3];
let mut h: HashMap<i32, ()> = HashMap::new();
for i in &v {
    h.insert(i, ());
}
error[E0308]: mismatched types
 --> src/main.rs:6:18
  |
6 |         h.insert(i, ());
  |                  ^ expected i32, found &i32
  |
  = note: expected type `i32`
             found type `&i32`

然后可以用*i替换要插入的key。

您的 HashMap 的完整类型被推断为 HashMap<&i32, i32>。这可以通过 using the following trick:

来验证
let () = h;

触发类型错误:

error[E0308]: mismatched types
  --> src/main.rs:17:9
   |
17 |     let () = h;
   |         ^^ expected struct `std::collections::HashMap`, found ()
   |
   = note: expected type `std::collections::HashMap<&{integer}, {integer}>`
              found type `()`

(此时编译器还不确定最终类型将是 HashMap<&i32, i32>,因此类型签名中的 {integer}s)

当你遍历 &h 时,(k, v) 元组的类型为 (&&i32, &i32)(也可以用上述技巧确认),这就是你需要双重解引用的原因k 只有一个 v.