【问题标题】:`HashMap::get_mut` leading to "returns reference to local value", any efficient work-around?`HashMap::get_mut` 导致“返回对本地值的引用”,任何有效的解决方法?
【发布时间】:2021-12-20 02:36:34
【问题描述】:

围绕这个问题有很多问题,解决方案大多是“使用Entry”。

但是这是一个问题,因为HashMap::entry() 需要一个拥有的值,这意味着即使密钥已经存在并且我们只想就地更新值,这也意味着可能昂贵的副本/分配,因此使用get_mut。然而,在对本地的引用上使用 get_mut 会导致 rustc 假设所述引用被存储到哈希图中,并且 thus that returning the hashmap is an error:

use std::borrow::Cow;
use std::collections::HashMap;

fn get_string() -> String { String::from("xxxxxxx") }
fn foo() -> HashMap<Cow<'static, str>, usize> {
    let mut v = HashMap::new();

    // stand-in for "get a string slice as key",
    // real case is getting a String from an 
    // mpsc and the key being a segment of that string
    let s = get_string();
    // stand-in for a structure which contains an `Option<Cow>`
    let k = Cow::from(&s[2..3]);

    // because of get_mut, `&s` is apparently considered to be stored in `v`?
    if let Some(e) = v.get_mut(&k) {
        *e += 1;
    } else {
        v.insert(Cow::from(k.into_owned()), 0);
    }

    v
}

请注意,第 9~13 行的操作是为了阐明模式的要点,但get_mut alone is sufficient to trigger the issue

有没有办法不影响效率,还是急切分配是唯一的办法? (注意:因为这是一个静态问题,像contains_keyget 这样的动态门显然不会做任何事情。

【问题讨论】:

  • 在这里使用 Cow 没有什么意义,你也应该更喜欢 entry,或者在你的情况下 entry_raw
  • @Stargateur 如 cmets 中所述,Cow 充当更复杂结构(包含牛)的替身。我猜raw_entry_mut 可能会工作,但它需要每晚仍然......
  • @Stargateur 显然是 it's being rejected 无论如何,因此建立它似乎是一个糟糕的主意。
  • 为了更加清晰,我试图将代码从字符串(非结构化且为了效率起见具有有限的灵活性)更新为更丰富的 enums-with-strings-as-associated-data... 当然由于 Borrow 的语义,你不能真正创建非平凡结构之间的关系,因为 Borrowed 总是通过引用返回。
  • 嗯,你可以直接拥有Cow,但那样可能会失去Cow本身的用途? play.rust-lang.org/…

标签: rust hashmap


【解决方案1】:

根据docsHashSet::get_mut() 需要&amp;Q 类型的值,这样哈希的键就实现了Borrow&lt;Q&gt;

你的哈希键是Cow&lt;'static, str&gt;,即implementsBorrow&lt;str&gt;。这意味着您可以使用&amp;Cow&lt;'static, str&gt;&amp;str。但是您在 'local 的某些生命周期内传递了 &amp;Cow&lt;'local, str&gt;。编译器尝试将 'local'static 匹配,并发出一条关于生命周期的令人困惑的错误消息。

解决方案实际上很简单,因为您可以从Cow 获得&amp;str,或者调用k.as_ref() 或执行&amp;*k,并且&amp;str 的生命周期不受限制:(playground)

let k = Cow::from(&s[2..3]);
if let Some(e) = v.get_mut(k.as_ref()) { /* ...*/ }

【讨论】:

    猜你喜欢
    • 2011-08-22
    • 2019-06-30
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    相关资源
    最近更新 更多