Can't collect an array to a hashmap

const fn generate_dictionary() -> HashMap<i32, i32> {
    [
        (10, 1),
        (100, 25),
        (1000, 168),
        (10000, 1229),
        (100000, 9592),
        (1000000, 664579),
        (10000000, 5761455),
    ]
    .into_iter()
    .collect()
}

Compiler says:

error[E0277]: a value of type HashMap<i32, i32> cannot be built from an iterator over elements of type &({integer}, {integer})
--> src/main.rs:12:19
|
12 | ].into_iter().collect()
| ^^^^^^^ value of type HashMap<i32, i32> cannot be built from std::iter::Iterator<Item=&({integer}, {integer})>
|
= help: the trait FromIterator<&({integer}, {integer})> is not implemented for HashMap<i32, i32>
error: aborting due to previous error
For more information about this error, try rustc --explain E0277.

However if I use a vector, it compiles but allocation is not allowed in const fn

Arrays don't give off their items by-value, they coerce into a slice and the resulting iterator iterates over references to each element. In your case, you might be able to fix it by adding a .copied() behind .into_iter().

But HashMap allocates, too… so you won't be able to do this in a const fn in any case. Since you have a very small array, couldn't you just use linear search instead? Or make sure it's sorted by its key (which it currently is), and perform binary search on it.

1 Like

Yes, looks like I can't generate the HashMap in compile time anyways so I just created it in the runtime as a premature optimization.

In Rust 1.51, you can now use std::array::IntoIter::new() for this.

9 Likes

Avoid using .into_iter().copied() and instead use .iter().copied(). They are functionally equivalent, but the former will break if Rust decides to implement IntoIterator for arrays in the future (which it is planning to do). The latter more explicitly takes the array by reference and so won't break.

6 Likes

Had this example included a larger array, given constant is not an option (using HashMap), would using a Vec not create an opportunity for better memory management?

... as useful as iter().copied() and now array.IntoIter.new() are, I see a lost opportunity to enable the option to reuse memory, something an array cannot do.

Reuse memory how? If you mean reuse the buffer of the Vec for the HashMap through specialization magic, that's not possible, because a linear-probing hash map with N entries contains strictly more memory slots than entries (IIRC this "load factor" in the case of the current implementation is something like 7/8), not to mention that each entry has to be marked as empty or occupied at least, so you can't directly reinterpret an existing [(K, V)] as the buffer of a hash map.

1 Like

For static data, another option is phf.

1 Like