snippetrustCritical
How do I create a HashMap literal?
Viewed 0 times
literalhowhashmapcreate
Problem
How I can create a HashMap literal in Rust? In Python I can do it so:
And in Go like this:
hashmap = {
'element0': {
'name': 'My New Element',
'childs': {
'child0': {
'name': 'Child For Element 0',
'childs': {
...
}
}
}
},
...
}
And in Go like this:
type Node struct {
name string
childs map[string]Node
}
hashmap := map[string]Node {
"element0": Node{
"My New Element",
map[string]Node {
'child0': Node{
"Child For Element 0",
map[string]Node {}
}
}
}
}
Solution
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
Rust 1.56
Many collections now offer conversions from an array argument using
This logic can be wrapped back into a macro for some syntax sugar:
Rust 1.51
As of Rust 1.51, you can use by-value array iterators and
Note that in Rust 1.53,
This logic can be wrapped back into a macro for some syntax sugar:
These solutions avoid both unneeded allocation and reallocation.
See also:
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:
This macro avoids allocating an unneeded intermediate
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.Context
Stack Overflow Q#27582739, score: 240
Revisions (0)
No revisions yet.