I am trying to extract the unique members of a collection of usize.
I have boiled my code down to:
let mut unique_things: HashMap<usize, bool> = HashMap::new();
unique_things[&5] = false;
The error message
error[E0594]: cannot assign to data in an index of `HashMap<usize, bool>`
--> src/main.rs:147:2
|
147 | unique_things[&5] = false;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<usize, bool>`
That's correct. It is a bit confusing that HashMap implements Index and not IndexMut. If we look at the definition of the trait though, it's fairly straightforward to see why implementing it for HashMap is fraught.
IndexMut returns an exclusive reference to the value based on the index parameter. That means the trait can really only return references to values that are already in the collection. Otherwise we'd need some sort of default value for the type to fill in that memory with before we created a reference to it.
Since most languages that support indexing syntax on map-like collections usually DO allow you to add items to the collection via indexing, it can be a little confusing for new users. That was at least part of the rationale for removing the implementation on the map types in std. There may eventually be another Index trait that allows assignment in a way that would support this but for now the dedicated methods are the way to go.
It means Idx can be a dynamically sized type, i.e. the compiler may not know the size of the type directly. Sized is currently the only trait you can use the ? syntax on to indicate it may or may not be implemented.
I'm not actually sure why that bound is there, it might be related to the currently unstable unsized_locals feature.
it's kinda related to that , but that's not the main reason.
it's because when you declare a trait or generic in any place the compiler implicitly adds a bound that it is Sized, so that (speculation) it can compile those without demanding Sized bounds everywhere until unsized_locals is stabilized. (/end speculation)
but in this case, since it takes a &mut self, it does not need the Sized bound, and so, to allow !Sized types too, hence the ?Sized stuff.
i'm not sure why the compiler is not smart enough to do these kinds of stuff automatically tho.
Right, but in Index T is a by-value parameter, so you can't actually implement it with a DST like Index<str> or Index<dyn Debug> without running face first into a compiler error (which happens to mention unsized_locals).