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

问题描述 投票:1回答:1

我在使用锈蚀参考时遇到了一些麻烦。我有以下不编译的代码:

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));(双&符号)代码编译

Questions:

  1. map.insert(&0, &0)将指向两个整数文字的指针插入到地图中。我不确定这是怎么回事,因为我没有在任何地方使用变量。我怎样才能引用文字?我期待编译器让我这样做:
let a = 0;
let b = 0
map.insert(&a, &b);

换句话说,&0甚至意味着什么?它是否为文字分配内存并返回对它的引用?如果是这样,那么我假设没有两个&0s会指向同一个内存吗?

  1. 为什么我要做Some(&&0)而不仅仅是Some(&0)&&0甚至意味着什么?据我所知,**ptr意味着两次取消引用变量以获取基础值。但我无法想象相反的情况 - 你怎么能“引用”两次整数文字?
rust
1个回答
4
投票

如果你看一下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调用get来获取&&K


如果您设法让编译器为您提供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

© www.soinside.com 2019 - 2024. All rights reserved.