Should there be a compiler error here?
LucasSte opened this issue · comments
I created the following example code:
use indexmap::IndexMap;
struct SaveSmth {
pub a: usize,
}
fn main() {
let mut imp : IndexMap<usize, SaveSmth> = IndexMap::new();
imp.insert(8, SaveSmth{a : 3});
let mut vec : Vec<(usize, usize)> = Vec::new();
vec.push((8, 1));
for item in vec {
let a = &imp[item.0];
println!("{}", a.a);
}
}
Rust panics in let a = &imp[item.0]
and the correct way to fetch the value should be let a = &imp[&item.0];
. Shouldn't there be a compiler error because I'm passing the wrong type to look up the table?
The panic message says "index out of bounds":
thread 'main' panicked at 'IndexMap: index out of bounds', src/main.rs:16:18
It's not an error, but I can see why you're surprised -- I even mentioned this possible confusion in #132.
There are two flavors of indexing here: Index<&Q>
for map-like key lookup (with Q: Equivalent<K>
), and Index<usize>
for vector-like indexing, which is the sort of capability that gives us "index" in the crate and type names. #177 also added indexing with usize
ranges to get a Slice
, but this is not published yet.
So when your K
is also usize
, there is an unfortunate footgun that map[i]
and map[&i]
are both valid, as far as the compiler is concerned, but only you know which is actually appropriate for that i: usize
.
I did not understand what indexing with usize
is supposed to return. In my example, if I indexed the map without an ampersand imp[item.0]
, what should that retrieve?
Index<&Q>
is by key, like a HashMap
, so imp[&item.0]
returns the entry with that given key.
Index<usize>
is by position, like Vec
, so imp[0]
is the first, imp[1]
is the second, etc., in the same order you get from the iterators. IndexMap
preserves the insertion order, unless you alter that with methods like swap or remove. For your example that has item.0 == 8
, imp[8]
is out of bounds because there is only one item in the map -- only imp[0]
is in bounds.