Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does indexing a HashMap not return a reference?

I am writing the follwing test code.

fn test() {
    let mut m = HashMap::new();
    m.insert("aaa".to_string(), "bbb".to_string());

    let a = m["aaa"];   // error [E0507] cannot move out of index of `HashMap<String, String>`
    let a  = m.index("aaa");  // ok, the type of a is &String. I think The compile will add & to m;
    let a :&String = (&m).index("aaa");  // ok, the type of a is &String.
    println!("{:?}", m["aaa"]);  // ok
}

I am not understand why the return type of m["aaa"] is String, not &String. Because the index(&self, key: &Q) -> &V of the trait Index has a &self parameter, I think the compile will add a & to m, and the return type of m["aaa"] should be &String, so String "bbb" will not be moved out of m.

If the compile does not add & to m, it will not find the index() method, the error should be like m cannot be indexed by "bbb";

like image 301
Joey Avatar asked Aug 30 '26 16:08

Joey


1 Answers

From the docs for Index:

container[index] is actually syntactic sugar for *container.index(index)

So what happens is that when you write m["aaa"], the compiler is actually adding a * that dereferences the value returned by Index::index, whereas when you call m.index ("aaa"), you get the &String reference directly.

As pointed out by @user4815162342, programmers are supposed to make their intent explicit by writing either &m["aaa"] or m["aaa"].clone().

Moreover println!("{:?}", m["aaa"]); works because the println! macro does add a & to all the values it accesses¹ to prevent accidental moves caused by display, and this cancels out the * added by the compiler.


(1) This is indirectly documented in the docs for the format_args! macro.

like image 122
Jmb Avatar answered Sep 01 '26 08:09

Jmb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!