Question
How can I create a HashMap literal in Rust?
In Python, I can write nested dictionary data like this:
hashmap = {
"element0": {
"name": "My New Element",
"childs": {
"child0": {
"name": "Child For Element 0",
"childs": {}
}
}
}
}
In Go, I can do something similar with a struct and a map:
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{}
},
},
},
}
What is the Rust equivalent for creating a HashMap, especially when the data is nested like this?
Short Answer
By the end of this page, you will understand why Rust does not have a built-in HashMap literal syntax like Python, and how to build HashMap values using HashMap::new(), insert(), arrays plus collect(), and helper macros. You will also see how to model nested data with structs and recursive types in idiomatic Rust.
Concept
Rust does not have a dedicated built-in literal syntax for HashMap values like Python's {} dictionary syntax. That is the key idea behind this question.
Instead, Rust usually creates HashMap values in one of these ways:
HashMap::new()and theninsert()items- build from an iterator using
.collect() - use a crate macro such as
maplit::hashmap!
Why Rust works this way
Rust keeps its core syntax small and explicit. A HashMap is not a special language construct. It is a type from the standard library:
use std::collections::HashMap;
Because it is a library type, Rust does not give it custom literal syntax the way arrays, tuples, or structs have.
Nested maps in Rust
When your data is nested, you usually have two design choices:
- Use nested
HashMaps directly - Use a struct for each node, and put nested
HashMaps inside the struct
For tree-like data such as your example, a struct is often clearer than storing everything as generic maps. It gives each field a name and a type.
Recursive data needs a concrete shape
In your example, each node contains:
- a
name - a map of children
That maps naturally to a Rust struct like this:
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
name: String,
childs: HashMap<String, Node>,
}
This is a recursive type: Node contains a HashMap whose values are also Node. That is valid because HashMap stores its contents indirectly on the heap, so the compiler can determine the size of Node.
Why this matters in real programming
This concept matters because in Rust, you often need to decide whether your data should be:
- a flexible key-value structure (
HashMap) - a strongly typed structure (
struct)
For configuration data, JSON-like dynamic values may be fine. For application logic, a struct is usually safer and easier to maintain.
In short:
- Rust has no native
HashMapliteral syntax - You create maps with constructors, iterators, or macros
- For nested tree data, structs are usually the most idiomatic solution
Mental Model
Think of a HashMap in Rust like a filing cabinet you assemble before use.
In Python, the language gives you a ready-made shorthand for filling the cabinet instantly:
{"key": "value"}
In Rust, the cabinet is a normal library tool, not built into the language grammar. So you either:
- create an empty cabinet and add folders one by one, or
- prepare a list of
(key, value)pairs and convert it into a cabinet
For nested data, imagine each folder contains:
- a label (
name) - another smaller filing cabinet (
childs)
That is exactly what a recursive Node struct represents.
Syntax and Examples
Basic HashMap creation with insert
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("language", "Rust");
map.insert("type", "systems");
println!("{:?}", map);
}
Explanation
HashMap::new()creates an empty mapinsert(key, value)adds entries- the map must be
mutbecause inserting changes it
Building a HashMap with collect()
use std::collections::HashMap;
fn main() {
let map: HashMap<&str, i32> = [
("a", 1),
("b", 2),
("c", 3),
]
.into_iter()
.collect();
println!("{:?}", map);
}
Explanation
- start with an array of key-value tuples
- turn it into an iterator
- collect it into a
HashMap
This is the closest standard-library style to a literal.
Nested struct example similar to the question
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
name: String,
childs: HashMap<String, Node>,
}
fn main() {
let child = Node {
name: "Child For Element 0".to_string(),
childs: HashMap::new(),
};
let mut children = HashMap::new();
children.insert("child0".to_string(), child);
let element0 = Node {
name: "My New Element".to_string(),
childs: children,
};
let mut hashmap = HashMap::new();
hashmap.insert("element0".to_string(), element0);
println!("{:#?}", hashmap);
}
Why this is idiomatic
- the data has a clear shape, so
struct Nodeis a good fit - each field has a known type
- nested
HashMap<String, Node>models child nodes naturally
A shorter version using HashMap::from
use std::collections::HashMap;
fn main() {
let map = HashMap::from([
("one", 1),
("two", 2),
]);
println!("{:?}", map);
}
This works well for simple maps, but nested values often become easier to read if you build them in steps.
Step by Step Execution
Consider this example:
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
name: String,
childs: HashMap<String, Node>,
}
fn main() {
let leaf = Node {
name: "Child For Element 0".to_string(),
childs: HashMap::new(),
};
let mut child_map = HashMap::new();
child_map.insert("child0".to_string(), leaf);
let root = Node {
name: "My New Element".to_string(),
childs: child_map,
};
let mut nodes = HashMap::new();
nodes.insert("element0".to_string(), root);
println!("{:#?}", nodes);
}
What happens step by step
1. Define the Node type
struct Node {
name: String,
childs: HashMap<String, Node>,
}
Each Node has:
- a
name - a
childsmap where each key is aStringand each value is anotherNode
2. Create the leaf node
let leaf = Node {
name: "Child For Element 0".to_string(),
childs: HashMap::new(),
};
This node has no children, so its childs field is an empty HashMap.
3. Create a map for children
let mut child_map = HashMap::new();
child_map.insert("child0".to_string(), leaf);
Now the child map contains one entry:
- key:
"child0" - value: the
leafnode
4. Create the parent node
let root = Node {
name: "My New Element".to_string(),
childs: child_map,
};
The parent node now owns the child_map.
5. Create the outer HashMap
let mut nodes = HashMap::new();
nodes.insert("element0".to_string(), root);
This gives the top-level map one entry:
- key:
"element0" - value: the parent node
6. Print the result
println!("{:#?}", nodes);
Because Node derives Debug, Rust can print the whole nested structure.
Real World Use Cases
Configuration trees
Applications often load nested settings such as:
- services
- environment names
- feature flags
- child resources
A HashMap<String, Node> can represent a flexible hierarchy.
Menus and navigation
Desktop apps, games, and admin panels often model menus as nested nodes:
- menu label
- submenu items
That is very similar to a node with child maps.
File or category trees
You may need to represent:
- folders and subfolders
- product categories and subcategories
- comments and replies
A recursive struct with child maps is a common solution.
Parsing JSON-like data into typed Rust structures
Even if incoming data is dynamic, developers often convert it into structs for safety. A nested HashMap inside a struct can be useful when child keys are not fixed ahead of time.
Caches and lookup tables
Nested maps are also useful when data is grouped in stages, such as:
- country -> city -> weather record
- user_id -> resource_name -> permissions
- project -> file -> metadata
Real Codebase Usage
In real Rust codebases, developers rarely try to force everything into raw nested HashMaps unless the data is truly dynamic.
Common pattern: use structs for known fields
If fields like name are always present, use a struct:
struct Node {
name: String,
childs: HashMap<String, Node>,
}
This is clearer than storing "name" and "childs" as string keys inside another map.
Common pattern: build data in stages
Instead of writing one huge nested expression, many developers build values step by step:
- create child nodes
- put them into a child map
- create the parent node
- insert the parent into the outer map
This improves readability and makes debugging easier.
Common pattern: helper constructors
Projects often add helper functions:
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
name: String,
childs: HashMap<String, Node>,
}
impl Node {
fn new(name: &str) -> Self {
Self {
name: name.to_string(),
childs: HashMap::new(),
}
}
}
This avoids repeating HashMap::new() and to_string() everywhere.
Validation and guard patterns
When building nested maps from input data, code often validates first:
- reject empty names
- prevent duplicate keys
- return early on parse errors
This keeps invalid structures from spreading through the program.
Serialization support
Real projects often derive traits like Serialize and Deserialize with serde so nested structs can be saved and loaded easily. That is one more reason structs are often preferred over generic map-heavy designs.
Common Mistakes
1. Expecting Python-style map literals
Broken expectation:
// This is not valid Rust
let map = {
"a": 1,
"b": 2,
};
Why it fails
Rust does not have built-in HashMap literal syntax.
Fix
Use HashMap::new(), insert(), HashMap::from, or collect().
2. Forgetting to import HashMap
Broken code:
fn main() {
let map = HashMap::new();
}
Fix
use std::collections::HashMap;
3. Forgetting mut when inserting
Broken code:
use std::collections::HashMap;
fn main() {
let map = HashMap::new();
map.insert("a", 1);
}
Why it fails
insert() mutates the map.
Fix
let mut map = HashMap::new();
4. Mixing &str and String unintentionally
Broken code:
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
name: String,
childs: HashMap<String, Node>,
}
fn main() {
let node = Node {
name: "hello",
childs: HashMap::new(),
};
}
Why it fails
"hello" is a &str, but the field expects a String.
Fix
name: "hello".to_string()
5. Using a map when a struct is better
Sometimes beginners try to model everything as key-value pairs:
use std::collections::HashMap;
let mut node = HashMap::new();
node.insert("name", "My New Element");
node.insert("childs", "...");
Why this is a problem
- values may need different types
- field names can be misspelled
- the compiler cannot help much
Better approach
Use a struct when the shape is known.
6. Making nested construction too dense
You can sometimes write deeply nested expressions, but they become hard to read quickly.
Better approach
Build inner values first, then compose outer values.
Comparisons
HashMap::new() + insert() vs collect() vs macro
| Approach | Best for | Pros | Cons |
|---|---|---|---|
HashMap::new() + insert() | readable step-by-step building | explicit, easy to debug | more lines of code |
array/iterator + collect() | small fixed maps | compact, standard library only | can be less readable when deeply nested |
HashMap::from([...]) | simple fixed maps | very concise | not ideal for large nested values |
macro like hashmap! | literal-like style | closest to Python-style writing | requires an external crate |
HashMap vs BTreeMap
| Type | Ordering | Typical use |
|---|---|---|
HashMap | no guaranteed order | fast general-purpose lookups |
BTreeMap | sorted by key | when you need deterministic sorted iteration |
Raw nested maps vs structs
| Approach | Good when | Drawback |
|---|---|---|
nested HashMaps | keys and structure are highly dynamic | weaker type safety |
struct with child map | most fields are known ahead of time | slightly more setup at first |
&str vs String for keys and values
| Type | Meaning | Use when |
|---|---|---|
&str | borrowed string slice | the text already exists elsewhere |
String | owned string | the map or struct should own the data |
For nested application data, String is often the easiest choice because the structure owns its contents.
Cheat Sheet
Quick reference
Import
use std::collections::HashMap;
Empty map
let mut map: HashMap<String, i32> = HashMap::new();
Insert values
map.insert("a".to_string(), 1);
map.insert("b".to_string(), 2);
Build from fixed pairs
let map = HashMap::from([
("a", 1),
("b", 2),
]);
Build with collect()
let map: HashMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();
Nested recursive struct
use std::collections::HashMap;
struct Node {
name: String,
childs: HashMap<String, Node>,
}
Helpful constructor pattern
impl Node {
fn new(name: &str) -> Self {
Self {
name: name.to_string(),
childs: HashMap::new(),
}
}
}
Rules to remember
- Rust has no built-in
HashMapliteral syntax - use
mutif you callinsert() - use
Stringwhen your struct owns text data - use a
structwhen the data shape is known - use
HashMapwhen keys are dynamic
Common edge cases
"text"is&str, notStringHashMapiteration order is not guaranteed- if you need sorted keys, consider
BTreeMap
FAQ
How do you create a HashMap literal in Rust?
Rust has no built-in HashMap literal syntax. You create maps with HashMap::new(), insert(), HashMap::from([...]), collect(), or a helper macro from a crate.
What is the closest thing to a dictionary literal in Rust?
For standard library code, HashMap::from([("a", 1), ("b", 2)]) is often the closest concise form for small maps.
Can a Rust struct contain a HashMap<String, Node> of itself?
Yes. A recursive type like that is valid because the HashMap stores its contents indirectly.
Should I use nested HashMaps or a struct in Rust?
Use a struct when fields are known, like name and childs. Use nested maps when keys or structure are dynamic.
Why does Rust require mut for HashMap::insert()?
Because insert() changes the map. Rust requires mutable bindings for values that will be modified.
Can I use string literals directly inside a HashMap<String, T>?
Not directly. String literals are &str. Convert them with .to_string() or String::from(...).
Is there a macro for easier HashMap creation in Rust?
Yes. External crates such as maplit provide macros like hashmap! for a more literal-like style.
Mini Project
Description
Build a small category tree in Rust using a recursive Node struct and nested HashMaps. This demonstrates how to model parent-child relationships in a strongly typed way, similar to menus, folder trees, or product categories.
Goal
Create a nested map of categories where each category has a name and zero or more child categories, then print the full structure.
Requirements
- Define a
Nodestruct with anamefield and achildsfield of typeHashMap<String, Node>. - Create at least one parent node and two child nodes.
- Store the parent node inside an outer
HashMap<String, Node>. - Print the final nested structure using debug output.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.