在 Rust 中取消引用字符串和 HashMap
Dereferencing strings and HashMaps in Rust
我试图了解 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 的 Trait 实现部分给出了解除引用 fn deref(&self) -> &str
那么这里发生了什么?
错误是由于 String
上的泛型函数 HashMap::get
在类型推断期间被编译器 select 编辑。但是你想要 HashMap::get
而不是 str
.
所以改变一下
println!("{:?}", roman2number.get(&r0.to_string()));
至
println!("{:?}", roman2number.get::<str>(&r0.to_string()));
使其明确。这有助于编译器 select 正确的函数。
查看 Playground here。
在我看来强制转换 Deref<Target>
只有在我们知道目标类型时才会发生,因此当编译器试图推断要使用哪个 HashMap::get
时,它会将 &r0.to_string()
视为输入 &String
但永远不要输入 &str
。并且 &'static str
没有实现 Borrow<String>
。这会导致类型错误。当我们指定 HashMap::get::<str>
时,此函数期望 &str
,此时可以对 &String
进行强制转换以获得匹配的 &str
.
您可以查看 Deref
coercion and String
Deref 了解更多详情。
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>
。根据 Borrow
的定义,这意味着 &'static str
需要转换为 &String
。但我读过的所有 docs/texts 都指出,无论你在何处使用 &String
,你都应该使用 &str
。因此,提供 &str
-> &String
转换毫无意义,即使有时它会让生活变得更轻松。
因为每个 reference type is borrowable as a shorter lived reference type.),当 &'static str
是键类型时,你可以传递 &str
,因为 &'static str
实现了 Borrow<str>
其他答案是正确的,但我想指出您有一个不需要的 to_string
(您已经 collect
编辑成 String
)和替代方法使用 as
:
强制转换为 &str
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));
}
}
请注意,地图无需显式类型,系统会自动推断。
我试图了解 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 的 Trait 实现部分给出了解除引用 fn deref(&self) -> &str
那么这里发生了什么?
错误是由于 String
上的泛型函数 HashMap::get
在类型推断期间被编译器 select 编辑。但是你想要 HashMap::get
而不是 str
.
所以改变一下
println!("{:?}", roman2number.get(&r0.to_string()));
至
println!("{:?}", roman2number.get::<str>(&r0.to_string()));
使其明确。这有助于编译器 select 正确的函数。
查看 Playground here。
在我看来强制转换 Deref<Target>
只有在我们知道目标类型时才会发生,因此当编译器试图推断要使用哪个 HashMap::get
时,它会将 &r0.to_string()
视为输入 &String
但永远不要输入 &str
。并且 &'static str
没有实现 Borrow<String>
。这会导致类型错误。当我们指定 HashMap::get::<str>
时,此函数期望 &str
,此时可以对 &String
进行强制转换以获得匹配的 &str
.
您可以查看 Deref
coercion and String
Deref 了解更多详情。
get
方法的定义如下
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
第一部分是您传递的对象类型:Q
。 Q
有限制。 Q
的条件是
- 键类型
K
需要在Q
上实现 Q
需要实现Hash
和Eq
特征。
Borrow
特性
将其替换为您的实际类型意味着键类型 &'static str
需要实现 Borrow<String>
。根据 Borrow
的定义,这意味着 &'static str
需要转换为 &String
。但我读过的所有 docs/texts 都指出,无论你在何处使用 &String
,你都应该使用 &str
。因此,提供 &str
-> &String
转换毫无意义,即使有时它会让生活变得更轻松。
因为每个 reference type is borrowable as a shorter lived reference type.),当 &'static str
是键类型时,你可以传递 &str
,因为 &'static str
实现了 Borrow<str>
其他答案是正确的,但我想指出您有一个不需要的 to_string
(您已经 collect
编辑成 String
)和替代方法使用 as
:
&str
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));
}
}
请注意,地图无需显式类型,系统会自动推断。