为什么借用的 HashMap 的键和值是通过引用访问的,而不是值?

Why are the keys and values of a borrowed HashMap accessed by reference, not value?

我有一个函数需要借用 HashMap,我需要按键访问值。为什么键和值是按引用而不是按值?

我的简化代码:

fn print_found_so(ids: &Vec<i32>, file_ids: &HashMap<u16, String>) {
    for pos in ids {
        let whatever: u16 = *pos as u16;
        let last_string: &String = file_ids.get(&whatever).unwrap();

        println!("found: {:?}", last_string);
    }
}

考虑将参数作为引用或值传递的语义:

  • 作为参考:没有所有权转让。被调用的函数只是借用了参数。

  • 作为值:被调用函数拥有参数的所有权,调用者可能不再使用它。

由于函数 HashMap::get 不需要键的所有权来查找元素,因此选择了限制较少的传递方法:通过引用。

另外,它没有return元素的值,只是一个参考。如果它 returned 值,HashMap 中的值将不再由 HashMap 拥有,因此将来无法访问。

虽然当密钥是 u16 时它似乎没有帮助,但请考虑如何使用更复杂的密钥,例如 String

在那种情况下,按值获取键通常意味着必须为每次查找分配和初始化一个新的 String,这会很昂贵。

TL;DR:Rust 不是 Java。

Rust 可能具有高级构造和数据结构,但它本质上是一种低级语言,正如其指导原则之一所说明的那样:你不需要为什么付费你不使用.

因此,该语言及其库将尽可能地尝试消除任何多余的成本,例如不必要地分配内存。

案例一:按值取键

如果键是 String,这意味着为每次查找分配(和释放)内存,而您可以使用只分配一次的本地缓冲区。

案例二:按值返回

按值返回意味着:

  • 您从容器中删除条目以将其提供给用户
  • 您复制容器中的条目以将其提供给用户

后者显然效率低下(复制意味着分配),前者意味着如果用户想要取回值,则必须再次插入,这意味着查找等......并且效率也很低。

简而言之,在这种情况下按值返回是低效的。

因此,就效率而言,Rust 采取了最合乎逻辑的选择,并在可行的情况下按价值传递 returns。