hashmap rust dereference borrowing

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

  1. el tipo de clave K necesita implementar el rasgo de Borrow sobre Q
  2. Q necesita implementar los rasgos Hash y Eq .

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>