Why is a reference required in .get()

I'm brand new to Rust and I'm working through the following example from the book:

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let team_name = String::from("Blue");
    let score = scores.get(&team_name);

    match score {
        Some(&v) => println!("{}", &v),
        None => println!("There is no value there.")
    }
}

Passing a reference here to scores.get obviously compiles and behaves as expected but, why can't score take ownership of team_name by writing let score = scores.get(team_name);? After I define score, I don't need team_name anymore (right?) so I don't see why I can't take ownership of it.

Also, can someone advise as to whether or not I should use a reference in the match statement? Code works fine either way and I don't know enough yet to reason through why I should/shouldn't borrow in this case.

The type signature of HashMap::get specifies that the k argument must be a reference, so you cannot ever pass an owned value to it, even if you don't care about giving ownership away. This signature is used because get doesn't need ownership of k to do its thing and because you commonly want to look up a key in a HashMap without giving it away in the process (e.g. if the keys are Strings, it's nice to be able to index using only a &str, without having to allocate a new String every time that will just get thrown away when get returns).

In principle the compiler could silently insert & in this situation, but not accepting such code is more consistent and less "magical", and it gives you confidence that once the code does compile you aren't accidentally giving away ownership without needing to (which is likely to cause a problem eventually at any rate).

For Copy types like i32 or Option<&i32> (which is the inferred type of score here) you should never bother to match on the borrowed value. For non-Copy types -- HashMap, String, etc. -- you should match on a borrow unless one of the match arms is doing something that requires ownership or a &mut. This is because if one of the match patterns has a binding, that will cause the matched value to be moved out of (unless you use ref), even if you don't need ownership of the new bound value.

2 Likes