【问题标题】:How can I keep a reference to a key after it has been inserted into a HashMap?将键插入 HashMap 后,如何保留对键的引用?
【发布时间】:2015-09-04 15:39:33
【问题描述】:

我想插入到 HashMap 中,但要保留一个不可变的借用键以传递到位置。在我的情况下,键是字符串。

这是一种方式:

use std::collections::HashMap;
let mut map = HashMap::new();
let id = "data".to_string();  // This needs to be a String
let cloned = id.clone();

map.insert(id, 5);

let one = map.get(&cloned);
let two = map.get("data");
println!("{:?}", (one, two));

但这需要克隆。

这个一直工作到 Rust 1.2.0:

use std::collections::HashMap;
use std::rc::Rc;
use std::string::as_string;

let mut map = HashMap::new();
let data = Rc::new("data".to_string()); // This needs to be a String
let copy = data.clone();
map.insert(data, 5);

let one = map.get(&copy);
let two = map.get(&*as_string("data"));
println!("{:?}", (one, two));

如何使用 Rust 1.2.0 完成此任务?

理想情况下,我希望将一个键放入 HashMap 但保留对它的引用,并允许我使用 &str 类型访问其中的元素,而无需额外分配。

【问题讨论】:

标签: rust


【解决方案1】:

简短的回答是你不能。当您在HashMap 中插入内容时,您转让所有权。这样做会使您可能对键的任何引用无效,因为键已移动到映射分配的内存中。

RFC 1194 (Set Recovery) 提出了一种方法来获取对HashSet(不是映射)存储的密钥的引用。还需要进一步的信息和研究来证明支持 HashMap 的合理性。但是,这仍然不会帮助您,因为您需要知道密钥(或可用于查找它的东西)才能再次查找它。但是,此时您已经将密钥放入集合中。

您的第二个解决方案有效,因为您实际上并未将 String 的所有权授予地图,而是将所有权授予了通过引用计数来模拟共享所有权的类型。 clone 调用只是增加引用计数,这模拟了许多动态语言如何解决这个问题。

use std::collections::HashMap;
use std::rc::Rc;

fn main() {
    let mut map = HashMap::new();
    let data = Rc::new("data".to_string());
    map.insert(data.clone(), 5);

    let v = map.get(&data);
    println!("{:?}", v);
}

一些不稳定的功能可能会对您有所帮助。效率最高的是HashMap::raw_entry_mut

#![feature(hash_raw_entry)]

use std::collections::HashMap;

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

    let (k, _v) = map
        .raw_entry_mut()
        .from_key(id)
        .or_insert_with(|| (String::from(id), 0));

    println!("{:?}", k);
}

一个更短但效率稍低的解决方案使用Entry::insert

#![feature(entry_insert)]

use std::collections::HashMap;

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

    let entry = map.entry(String::from(id)).insert(0);
    let k = entry.key();

    println!("{:?}", k);
}

另见:

【讨论】:

  • 这个解决方案很棒!虽然我不能再使用&str 类型访问我的地图中的数据,但这是必须的。 ://
  • 这个 RFC 看起来像我需要的,可惜没有考虑 HashMaps。
  • 添加一个返回对新插入数据的引用的fn insert_and_get(&mut self, value: T) -> &T 在技术上是否困难或不可能?
  • @FrenchBoiethios 我不认为这很难或不可能,不。我自己也没有尝试过:-)
  • 仅供参考,有人可以提出一个实现:github.com/rust-lang/rust/pull/60142#issuecomment-487416553
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-06
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
相关资源
最近更新 更多