Search code examples
hashmaprustdereferenceborrowing

Dereferencing strings and HashMaps in Rust


I'm trying to understand how HashMaps work in Rust and I have come up with this example.

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
}

When I try to compile the code with last line uncommented, I get the following 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

The Trait implementation section of the docs gives the dereferencing as fn deref(&self) -> &str

So what is happening here?


Solution

  • The error is caused by that generic function HashMap::get over String is selected by the compiler during type inference. But you want HashMap::get over str.

    So just change

    println!("{:?}", roman2number.get(&r0.to_string()));
    

    to

    println!("{:?}", roman2number.get::<str>(&r0.to_string()));
    

    to make it explicit. This helps the compiler to select the right function.

    Check out Playground here.

    It looks to me that coercion Deref<Target> can only happen when we know the target type, so when compiler is trying to infer which HashMap::get to use, it sees &r0.to_string() as type &String but never &str. And &'static str does not implement Borrow<String>. This results a type error. When we specify HashMap::get::<str>, this function expects &str, when coercion can be applied to &String to get a matching &str.

    You can check out Deref coercion and String Deref for more details.