HashMap<String, T> for Dynamic JSON Keys
Use HashMap<String, T> when JSON object keys are not known in advance. Covers serde_json::Value, typed maps, and BTreeMap alternatives.
Detailed Explanation
Handling Dynamic Keys with HashMap
When a JSON object's keys are not known at compile time — feature flags, metric names, dynamic labels — you cannot define a struct. Instead, use HashMap<String, T>.
Example JSON
{
"metrics": {
"cpu_usage": 72.5,
"memory_usage": 85.3,
"disk_io": 45.1
},
"labels": {
"env": "production",
"region": "us-east-1"
}
}
Recommended Rust
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
pub metrics: HashMap<String, f64>,
pub labels: HashMap<String, String>,
}
The auto-converter cannot infer that an object should be a HashMap from a single sample. After pasting, replace the generated nested struct with HashMap<String, T> when you know the keys are dynamic.
Mixed value types
If values have different types ({ "theme": "dark", "fontSize": 14 }), use HashMap<String, serde_json::Value> and pattern-match on the variant at runtime:
match settings.get("theme") {
Some(serde_json::Value::String(s)) => println!("Theme: {}", s),
_ => {}
}
Ordered iteration
HashMap iteration order is unspecified. If you need deterministic output (for diffing, snapshot testing, or stable CLI output), use BTreeMap<String, T> instead — it iterates in sorted key order with the same serde derive support.
When to prefer a struct
If the same set of keys always appears, define a struct. Maps are slower at runtime, lose autocomplete, and bypass compile-time checks. Reach for HashMap only when the keys really do vary.
Use Case
Monitoring dashboards, feature flag systems, and Kubernetes-style label maps return arbitrary key/value pairs. Modeling them as HashMap lets you ingest the data without an explosion of one-off struct definitions.