【问题标题】:Why are the keys and values of a borrowed HashMap accessed by reference, not value?为什么借用的 HashMap 的键和值是通过引用而不是值访问的?
【发布时间】:2016-10-09 18:13:10
【问题描述】:

我有一个函数需要一个借来的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);
    }
}
  • 为什么我必须指定密钥作为参考,即file_ids.get(&amp;whatever).unwrap() 而不是file_ids.get(whatever).unwrap()

  • 据我了解,last_string 必须是 &amp;String 类型,表示借用字符串,因为拥有的集合是借用的。对吗?

  • 与上述观点类似,我是否正确假设 pos&amp;u16 类型,因为它从 ids 获取借用值?

【问题讨论】:

  • 好的,知道了。来自其他开发世界,这有时可以帮助我更清楚地看到&amp; 标志..

标签: collections rust ownership borrowing


【解决方案1】:

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

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

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

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

另外,它不返回元素的值,只返回一个引用。如果它返回该值,则HashMap 中的值将不再由HashMap 拥有,因此将来无法访问。

【讨论】:

  • 简而言之:因为它最便宜。
  • 有道理,谢谢。最让我困惑的是`&whatever`。我希望简单的 u16 可以按值复制(这可能比复制 64 位值作为指针更高效)。
  • @stej a u16 可以按值复制。然而,由于HashMap 是通用的,它被构建为对其他不可复制的类型有用。如果需要,您可以随时复制/克隆引用以获取 u16
【解决方案2】:

虽然当密钥是 u16 时似乎没有帮助,但想想它如何与更复杂的密钥(例如 String)一起工作。

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

【讨论】:

    【解决方案3】:

    TL;DR:Rust 不是 Java。

    Rust 可能具有高级构造和数据结构,但它本质上是一种低级语言,正如它的指导原则之一所示:你不为你不付出的东西买单使用

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

    案例 1:按值取键。

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

    案例 2:按值返回。

    按值返回意味着:

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

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

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

    因此,就效率而言,Rust 采取了最合乎逻辑的选择,并在可行时按值传递和返回。

    【讨论】:

    • 感谢您的评论。我多次阅读有关所有权的信息,但有时它并没有在我的脑海中点击;)然后更多信息很有用。
    猜你喜欢
    • 1970-01-01
    • 2010-12-20
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    相关资源
    最近更新 更多