How do I create a HashMap literal?

Starting with Rust 1.56, you can initialize a HashMap using from(), which is somewhat like having a HashMap literal. from() takes an array of key-value pairs. You can use it like this:

use std::collections::HashMap;

fn main() {
    let hashmap = HashMap::from([
        ("foo", 1),
        ("bar", 2)
    ]);
}

There isn't a map literal syntax in Rust. I don't know the exact reason, but I expect that the fact that there are multiple data structures that act maplike (such as both BTreeMap and HashMap) would make it hard to pick one.

Rust 1.56

Many collections now offer conversions from an array argument using From or Into:

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};

fn main() {
    let s = Vec::from([1, 2, 3]);
    println!("{:?}", s);

    let s = BTreeSet::from([1, 2, 3]);
    println!("{:?}", s);

    let s = HashSet::from([1, 2, 3]);
    println!("{:?}", s);

    let s = BTreeMap::from([(1, 2), (3, 4)]);
    println!("{:?}", s);

    let s = HashMap::from([(1, 2), (3, 4)]);
    println!("{:?}", s);
}

This logic can be wrapped back into a macro for some syntax sugar:

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};

macro_rules! collection {
    // map-like
    ($($k:expr => $v:expr),* $(,)?) => {{
        core::convert::From::from([$(($k, $v),)*])
    }};
    // set-like
    ($($v:expr),* $(,)?) => {{
        core::convert::From::from([$($v,)*])
    }};
}

fn main() {
    let s: Vec<_> = collection![1, 2, 3];
    println!("{:?}", s);

    let s: BTreeSet<_> = collection! { 1, 2, 3 };
    println!("{:?}", s);

    let s: HashSet<_> = collection! { 1, 2, 3 };
    println!("{:?}", s);

    let s: BTreeMap<_, _> = collection! { 1 => 2, 3 => 4 };
    println!("{:?}", s);

    let s: HashMap<_, _> = collection! { 1 => 2, 3 => 4 };
    println!("{:?}", s);
}

Rust 1.51

As of Rust 1.51, you can use by-value array iterators and FromIterator to collect into many kinds of collections:

use std::array::IntoIter;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::iter::FromIterator;

fn main() {
    // Rust 1.53
    let s = Vec::from_iter([1, 2, 3]);
    println!("{:?}", s);

    // Rust 1.51
    let s = Vec::from_iter(IntoIter::new([1, 2, 3]));
    println!("{:?}", s);

    let s = BTreeSet::from_iter(IntoIter::new([1, 2, 3]));
    println!("{:?}", s);

    let s = HashSet::<_>::from_iter(IntoIter::new([1, 2, 3]));
    println!("{:?}", s);

    let s = BTreeMap::from_iter(IntoIter::new([(1, 2), (3, 4)]));
    println!("{:?}", s);

    let s = HashMap::<_, _>::from_iter(IntoIter::new([(1, 2), (3, 4)]));
    println!("{:?}", s);
}

Note that in Rust 1.53, std::array::IntoIter isn't always needed.

This logic can be wrapped back into a macro for some syntax sugar:

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};

macro_rules! collection {
    // map-like
    ($($k:expr => $v:expr),* $(,)?) => {{
        use std::iter::{Iterator, IntoIterator};
        Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*]))
    }};
    // set-like
    ($($v:expr),* $(,)?) => {{
        use std::iter::{Iterator, IntoIterator};
        Iterator::collect(IntoIterator::into_iter([$($v,)*]))
    }};
}

fn main() {
    let s: Vec<_> = collection![1, 2, 3];
    println!("{:?}", s);

    let s: BTreeSet<_> = collection! { 1, 2, 3 };
    println!("{:?}", s);

    let s: HashSet<_> = collection! { 1, 2, 3 };
    println!("{:?}", s);

    let s: BTreeMap<_, _> = collection! { 1 => 2, 3 => 4 };
    println!("{:?}", s);

    let s: HashMap<_, _> = collection! { 1 => 2, 3 => 4 };
    println!("{:?}", s);
}

These solutions avoid both unneeded allocation and reallocation.

See also:

  • Add hashmap, hashset, treemap, and treeset macros

Previous versions

You can create a macro to do the job for you, as demonstrated in Why does this rust HashMap macro no longer work?. Here is that macro simplified a bit and with enough structure to make it runnable in the playground:

macro_rules! map(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

fn main() {
    let names = map!{ 1 => "one", 2 => "two" };
    println!("{} -> {:?}", 1, names.get(&1));
    println!("{} -> {:?}", 10, names.get(&10));
}

This macro avoids allocating an unneeded intermediate Vec, but it doesn't use HashMap::with_capacity so there may be some useless reallocations of the HashMap as values are added. A more complicated version of the macro that counts the values is possible, but the performance benefits are probably not something most uses of the macro would benefit from.


There is an example of how to achieve this in the documentation for HashMap:

let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
    .iter()
    .cloned()
    .collect();

I recommend the maplit crate.

To quote from the documentation:

Macros for container literals with specific type.

use maplit::hashmap;

let map = hashmap!{
    "a" => 1,
    "b" => 2,
};

The maplit crate uses => syntax for the mapping macros. It is not possible to use : as separator due to syntactic the restrictions in regular macro_rules! macros.

Note that rust macros are flexible in which brackets you use for the invocation. You can use them as hashmap!{} or hashmap![] or hashmap!(). This crate suggests {} as the convention for the map & set macros, it matches their Debug output.

Macros

  • btreemap Create a BTreeMap from a list of key-value pairs
  • btreeset Create a BTreeSet from a list of elements.
  • hashmap Create a HashMap from a list of key-value pairs
  • hashset Create a HashSet from a list of elements.

Tags:

Hashmap

Rust