定义一个HashMap,如下,在get的时候,如果传入value.as_str()编译通过,传入&value提示
the trait Borrow<std::string::String>
is not implemented for &str
,
value.as_str()的类型不也是&str吗
lazy_static! {
static ref OPERATIONS_MAP: HashMap<&'static str, u32> = {
let mut map = HashMap::new();
map.insert("create user", 1);
map.insert("delete user", 2);
map
};
}
impl LogOperation {
fn parse(value: String) -> Result<LogOperation, String> {
if let Some(operation_number) = OPERATIONS_MAP.get(&value) {
//if let Some(operation_number) = OPERATIONS_MAP.get(value.as_str())
return Ok(Self(*operation_number));
}
return Err(format!("{} is not a valid operation.", value));
}
}
1
共 3 条评论, 1 页
评论区
写评论感谢各位回答, 又学习到了
你需要的是
OPERATIONS_MAP.get(&*value)
,或者任何得到直接&str
的方法。尽量去理解编译器告诉你的信息:
已经确定
K = &str
,V = u32
,Q = String
,那么根据约束条件,你能得到&str: Borrow<String>
吗?编译器正是告诉你不能得到 —— 去搜索
Borrow
trait 文档,发现这么几条相关的实现:仔细比对(固定 K = &str),只有:
显然没有
&str: Borrow<String>
。而
&str: Borrow<String>
其实是不可能的,根据定义:当传入
&*value
之类的值,其类型为&str
,即Q = str
,有&str: Borrow<str>
,所以代码通过。总结:Rust 的泛型和方法是靠推导的。
嗯,继续思考的话,可能会问,
&String
和&str
不是一样吗? coercion 就让代码通过了啊。只要你在某个地方明确指明类型,当然可以利用 coercion 进行转换:
OPERATIONS_MAP.get::<str>(&value)
但没指明任何类型的泛型情况下,Rust 不对
&String
做强制转换,也没有错。我感觉是因为HashMap的get参数类型是generic的,所以coercion没能正常工作。
展开解释一下:
正常情况下如果形参类型是&str而实参类型是&String,因为String实现了Deref<Target=str>,所以可以coerce过去。
但是对于get这个函数,它的参数类型是Q且要求满足K: Borrow,也就是要求HashMap的key: K能产生一个Q的借用(背后的设计思路是HashMap是持有所有key的ownership的,所以总可以对K随便借用)。看起来rustc在处理这种形参类型不确定的情况时,不会做coercion。
https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.get
https://doc.rust-lang.org/reference/type-coercions.html#coercion-sites
https://doc.rust-lang.org/std/borrow/trait.Borrow.html