本文介绍了将键插入 HashMap 后,如何保留对键的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to insert into a HashMap but keep an immutable borrow of the key to pass around to places. In my case the keys are strings.

这是一种方式:

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:

This one worked until 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 完成此操作?

How can I accomplish this with Rust 1.2.0?

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

Ideally I would want to put a key into a HashMap but keep a reference to it, and allow me to access elements in it with &str types, with no extra allocating.

推荐答案

简短的回答是你不能.当你在 HashMap 中插入一些东西时,你转移了所有权.这样做会使您可能拥有的对键的任何引用无效,因为键被移动到映射分配的内存中.

The short answer is that you can't. When you insert something into the HashMap, you transfer ownership. Doing so invalidates any references that you might have to the key, as the key is moved into the memory allocated by the map.

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

RFC 1194 (Set Recovery) proposes a way to get references to the key stored by a HashSet (not map). Further information and research was needed to justify supporting this for HashMap as well. However, this still wouldn't help you as you would need to know the key (or something that can be used to look it up) in order to look it up again. However, you've already put the key in the collection at that point.

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

Your second solution works because you aren't actually giving ownership of the String to the map, you are giving it ownership of a type that models shared ownership via reference counting. The clone call simply increments the reference count, and this models how a lot of dynamic languages would solve this problem.

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

A shorter but slightly less efficient solution uses 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);
}

另见:

这篇关于将键插入 HashMap 后,如何保留对键的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 09:26