Desconferencia de cadenas y HashMaps en Rust
dereference borrowing (3)
Las otras respuestas son correctas, pero quería señalar que usted tiene una to_string
innecesaria (ya ha collect
ed en una String
) y una forma alternativa de forzar a una &str
, usando as
:
let r0: String = roman_num.chars().take(1).collect();
println!("{:?}", roman2number.get(&r0 as &str));
En este caso, probablemente solo reescribo el mapa para contener char
como la clave:
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));
}
}
Tenga en cuenta que no es necesario tener un tipo explícito para el mapa, se deducirá.
Estoy tratando de entender cómo funcionan los HashMaps en Rust y se me ocurrió este ejemplo.
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
}
Cuando intento compilar el código con la última línea sin comentario, aparece el siguiente error
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
La sección de implementación de Trait de los documentos da la desreferenciación como fn deref(&self) -> &str
Entonces, ¿Que esta pasando aquí?
El error es causado por esa función genérica HashMap::get
over String
es seleccionada por el compilador durante la inferencia de tipo. Pero quieres HashMap::get
el str
.
Así que solo cambia
println!("{:?}", roman2number.get(&r0.to_string()));
a
println!("{:?}", roman2number.get::<str>(&r0.to_string()));
para hacerlo explícito. Esto ayuda al compilador a seleccionar la función correcta.
Echa un vistazo a Playground aquí .
Me parece que la coerción Deref<Target>
solo puede ocurrir cuando conocemos el tipo de destino, por lo que cuando el compilador intenta inferir qué HashMap::get
usar, ve a &r0.to_string()
como tipo &String
pero nunca &str
. Y &''static str
no implementa Borrow<String>
. Esto produce un error de tipo. Cuando especificamos HashMap::get::<str>
, esta función espera &str
, cuando la coerción se puede aplicar a &String
para obtener una coincidencia &str
.
Puedes ver la coerción de Deref
y String
Deref para más detalles.
La definición del método get
se ve de la siguiente manera
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
La primera parte es el tipo de objeto que pasas: Q
Hay restricciones en Q
Las condiciones en Q
son eso
- el tipo de clave
K
necesita implementar el rasgo deBorrow
sobreQ
-
Q
necesita implementar los rasgosHash
yEq
.
Reemplazar esto con sus tipos reales significa que key-type &''static str
necesita implementar Borrow<String>
. Según la definición de Borrow
, esto significa que a &''static str
necesita ser convertible a &String
. Pero todos los documentos / textos que he leído indican que en todos los lugares que use &String
debería usar &str
lugar. Por lo tanto, tiene poco sentido ofrecer una conversión de &str
-> &String
, incluso si a veces la vida es un poco más fácil.
Dado que cada tipo de referencia es prestablecida como un tipo de referencia de vida más corta .), Puede pasar un &str
cuando &''static str
es el tipo de clave, porque &''static str
implementa Borrow<str>