我试图了解HashMaps在Rust中是如何工作的,我已经提出了这个例子。
use std::collections::HashMap;
fn main() {
let mut roman2number: HashMap<&'static str, i32> = HashMap::new();
roman2number.insert("X", 10);
roman2number.insert("I", 1);
let roman_num = "XXI".to_string();
let r0 = roman_num.chars().take(1).collect::<String>();
let r1: &str = &r0.to_string();
println!("{:?}", roman2number.get(r1)); // This works
// println!("{:?}", roman2number.get(&r0.to_string())); // This doesn't
}
当我尝试编译最后一行未注释的代码时,我收到以下错误
error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277]
println!("{:?}", roman2number.get(&r0.to_string()));
^~~
note: in this expansion of format_args!
note: in this expansion of print! (defined in <std macros>)
note: in this expansion of println! (defined in <std macros>)
help: run `rustc --explain E0277` to see a detailed explanation
docs的特征实施部分将解除引用设为fn deref(&self) -> &str
那么这里发生了什么?
答案 0 :(得分:13)
错误是由类型推断期间编译器选择String
以上的泛型函数HashMap::get
引起的。但您希望HashMap::get
超过str
。
所以只需改变
println!("{:?}", roman2number.get(&r0.to_string()));
到
println!("{:?}", roman2number.get::<str>(&r0.to_string()));
使其明确。这有助于编译器选择正确的函数。
我认为强制Deref<Target>
只有在我们知道目标类型时才会发生,因此当编译器试图推断使用哪个HashMap::get
时,它会将&r0.to_string()
视为类型{ {1}}但永远不会&String
。 &str
未实现&'static str
。这会导致类型错误。当我们指定Borrow<String>
时,如果可以将强制应用于HashMap::get::<str>
以获得匹配的&str
,则此函数需要&String
。
您可以查看Deref
coercion和String
Deref了解详情。
答案 1 :(得分:5)
其他答案是正确的,但我想指出您有一个不需要的to_string
(您已经collect
加入String
)和另一种强制方式使用&str
:
as
let r0: String = roman_num.chars().take(1).collect();
println!("{:?}", roman2number.get(&r0 as &str));
在这个的情况下,我可能只是重写地图以包含char
作为关键:
use std::collections::HashMap;
fn main() {
let mut roman2number = HashMap::new();
roman2number.insert('X', 10);
roman2number.insert('I', 1);
let roman_num = "XXI";
for c in roman_num.chars() {
println!("{:?}", roman2number.get(&c));
}
}
请注意,不需要为地图提供明确的类型,它将被推断出来。
答案 2 :(得分:3)
get
方法的定义如下
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
第一部分是您传递的对象类型:Q
。 Q
有约束。 Q
上的条件是
K
需要在Q
Borrow
特征
Q
需要实施Hash
和Eq
特征。将其替换为实际类型意味着密钥类型&'static str
需要实现Borrow<String>
。根据{{1}}的定义,这意味着Borrow
需要转换为&'static str
。但我读过的所有文档/文字都表明,无论您使用&String
的所有地方,都应使用&String
代替&str
。因此提供&str
- &gt;是没有意义的。 &String
转换,即使它有时会让生活变得更轻松。
由于每个reference type is borrowable as a shorter lived reference type。),当&str
是密钥类型时,您可以传递&'static str
,因为&'static str
实现了Borrow<str>