Rust HashMap:为什么我需要双“&”号?

时间:2019-03-04 12:10:12

标签: rust

我在参考锈方面遇到了麻烦。我有以下无法编译的代码:

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();

    map.insert(&0, &0);
    map.insert(&1, &1);

    assert_eq!(map.get(&0), Some(&0));
}

我得到的编译错误是:

error[E0308]: mismatched types
 --> rust_doubt.rs:9:5
  |
9 |     assert_eq!(map.get(&0), Some(&0));
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &{integer}, found integral variable
  |
  = note: expected type `std::option::Option<&&{integer}>`
             found type `std::option::Option<&{integer}>`
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error: aborting due to previous error

果然,如果我换行:

assert_eq!(map.get(&0), Some(&0));assert_eq!(map.get(&0), Some(&&0));(双“&”号)代码编译

问题:

  1. map.insert(&0, &0)将指向两个整数文字的指针插入映射。我不确定这怎么可能,因为我没有在任何地方使用变量。如何引用文字?我期望编译器使我做到这一点:
let a = 0;
let b = 0
map.insert(&a, &b);

换句话说,&0到底是什么意思?它是否为文字分配内存并返回对其的引用?如果是这样,那我假设没有两个&0指向相同的内存是正确的吗?

  1. 为什么我必须要做Some(&&0)而不仅仅是Some(&0)&&0到底是什么意思?我了解**ptr意味着两次对变量进行解引用以获取基础值。但是我无法完全想象相反的情况-您如何两次“引用”整数文字?

1 个答案:

答案 0 :(得分:3)

如果您查看insertget的签名,您会发现它们对事物的处理方式不同。

HashMap<K, V>开始:

  • fn insert(&mut self, k: K, v: V) -> Option<V>
  • fn get(&self, k: &K) -> Option<&V>(简体)。

如您所见,insert获得所有权,处理,而get获得并返回引用

因此,如果您insert &1,则get Some(&&1)返回:多了一层参考。


那么问题是,为什么.get(&0)不会出现错误:它是否缺乏参考水平?

好吧,我欺骗并简化了get的签名,the exact signature是:

pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
    K: Borrow<Q>,
    Q: Hash + Eq, 

事实证明,&T实现了Borrow<T>,因此您可以使用&K来为&&K调用get。


如果您设法使编译器为您提供HashMap的类型,那么会容易一些:

assert_eq!(map, ());

结果:

error[E0308]: mismatched types
 --> src/main.rs:9:5
  |
9 |     assert_eq!(map, ());
  |     ^^^^^^^^^^^^^^^^^^^^ expected struct `std::collections::HashMap`, found ()
  |
  = note: expected type `std::collections::HashMap<&{integer}, &{integer}>`
             found type `()`
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

哪个显示了编译器为KV找出的类型,实际上是&{integer},因为您将&0传递给insert按键值对键值。


关于寿命问题:

  1. 并非所有检查都在一次通过中完成。特别是,借用/终生检查通常是在 类型检查之后进行的。
  2. 文学的寿命为'static,就像"Hello"的寿命为&'static str一样。

编译器会自动在程序中的某个地方保留文字,并在需要时“借用”它们。这意味着创建对文字整数的引用非常好:&0i32具有类型&'static i32