如何使用Box <String>作为具有&str键的哈希图的查找键?

时间:2019-12-17 22:50:26

标签: string types rust reference hashmap

预计我的哈希映射键的类型为&str,尤其是&'static str,并且我收到了自己的Box<String>
如何针对我的哈希图搜索字符串?

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<&str, u32> = HashMap::new();
    let static_string = "a";
    map.insert(static_string, 5);

    let owned_boxed_string = Box::new(String::from("a"));

    map.get(owned_boxed_string); // mismatched type (ok)
    map.get(*owned_boxed_string); // mismatched type (ok)
    map.get(&*owned_boxed_string); // trait bound not satisfied (?)
} 

1 个答案:

答案 0 :(得分:2)

让我们看看HashMap::get()的定义:

pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
    K: Borrow<Q>,
    Q: Hash + Eq, 

在您的代码中,K&'static str,并且从对Q的每次调用中推导出get。用简单的英语来说,get()引用了类型Q,使得&'static str实现了Borrow<Q>

基本原理是通常您将存储类型为String的键,等等,并且您将使用类型为&str的值进行搜索。自然,String实现了Borrow<str>,因此您可以做到这一点。

在您的情况下,您的密钥不是String而是&'static str ...查看Borrow的文档并查看实现了哪种Borrow<Q>&'static str。我只能看到这两个总体实现:

impl<'_, T: ?Sized> Borrow<T> for &'_ T
impl<T: ?Sized> Borrow<T> for T

第一个陈述指出,如果您的映射键是对某些类型&K的引用,则可以调用get(k: &K)。第二个则说,如果您的密钥是K,则可以呼叫get(k: &K)

因此对于您的&'static str的特殊情况,它们被实现为:

impl Borrow<str> for &'static str
impl Borrow<&'static str> for &'static str

由此可以推断出您的函数是get(k: &str)get(k: &&str)。最简单的选择是第一个。

现在,您可能会认为最后一行(map.get(&*owned_boxed_string);)应该有效,因为该值的类型为&str,但实际上不是,它的类型为&String。如果HashMap::get()收到了&str,则可以正常编译,但是如果使用Borrow<Q>,则编译器会感到困惑,并且失败。

TL; DR; :添加类型强制转换或临时类型变量:

map.get(&*owned_boxed_string as &str);  //ok
map.get(&owned_boxed_string as &str);   //also ok

let s: &str = &*owned_boxed_string;
map.get(s);
let s: &str = &owned_boxed_string;
map.get(s);

尽管更简单的解决方案(感谢@harmic用于下面的评论)是使用String::as_str(),它可以处理所需的所有deref并仅返回必要的&str

map.get(owned_boxed_string.as_str());