---
title: "HashMap\u003cK,V\u003e em Rust"
url: "https://rustlang.com.br/stdlib/hashmap/"
markdown_url: "https://rustlang.com.br/stdlib/hashmap.MD"
description: "Guia completo de HashMap em Rust: criação, inserção, busca, entry API, iteração, contagem de ocorrências e padrões práticos em português."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# HashMap<K,V> em Rust

Guia completo de HashMap em Rust: criação, inserção, busca, entry API, iteração, contagem de ocorrências e padrões práticos em português.


## O que é HashMap\<K,V\>

O `HashMap<K,V>` é uma coleção de pares chave-valor onde cada chave é única. Internamente, ele usa uma tabela hash para oferecer inserção, busca e remoção em tempo O(1) amortizado. As chaves devem implementar os traits `Eq` e `Hash` — tipos como `String`, `&str`, inteiros e tuplas desses tipos funcionam nativamente.

Use `HashMap` quando precisar associar dados a identificadores únicos: contar ocorrências de palavras, cachear resultados, mapear IDs a registros, ou qualquer situação onde o acesso rápido por chave é mais importante que a ordem dos elementos. Se precisar de ordem de inserção, considere `IndexMap` (crate externo) ou `BTreeMap` (que ordena por chave).

---

## Criando HashMaps

```rust
use std::collections::HashMap;

fn main() {
    // HashMap vazio
    let mut mapa: HashMap<String, i32> = HashMap::new();
    mapa.insert("um".to_string(), 1);

    // Com capacidade pré-alocada
    let mut mapa2: HashMap<&str, i32> = HashMap::with_capacity(100);
    mapa2.insert("dois", 2);

    // A partir de tuplas com collect
    let mapa3: HashMap<&str, i32> = vec![
        ("um", 1),
        ("dois", 2),
        ("três", 3),
    ].into_iter().collect();

    // A partir de arrays de tuplas (Rust 1.56+)
    let mapa4 = HashMap::from([
        ("vermelho", "#FF0000"),
        ("verde", "#00FF00"),
        ("azul", "#0000FF"),
    ]);

    // A partir de dois vetores com zip
    let chaves = vec!["a", "b", "c"];
    let valores = vec![1, 2, 3];
    let mapa5: HashMap<&str, i32> = chaves.into_iter().zip(valores).collect();

    println!("{mapa3:?}");
    println!("{mapa4:?}");
    println!("{mapa5:?}");
}
```

---

## Tabela de Métodos Principais

| Método | Descrição | Exemplo |
|---|---|---|
| `insert(k, v)` | Insere ou sobrescreve; retorna valor anterior | `m.insert("a", 1)` |
| `get(&k)` | Retorna `Option<&V>` | `m.get("a")` → `Some(&1)` |
| `get_mut(&k)` | Retorna `Option<&mut V>` | `m.get_mut("a")` |
| `contains_key(&k)` | Verifica se a chave existe | `m.contains_key("a")` |
| `remove(&k)` | Remove e retorna `Option<V>` | `m.remove("a")` |
| `entry(k)` | Retorna uma `Entry` para manipulação condicional | `m.entry("a").or_insert(0)` |
| `len()` | Número de pares | `m.len()` |
| `is_empty()` | Verifica se está vazio | `m.is_empty()` |
| `keys()` | Iterador sobre as chaves | `m.keys()` |
| `values()` | Iterador sobre os valores | `m.values()` |
| `values_mut()` | Iterador mutável sobre os valores | `m.values_mut()` |
| `iter()` | Iterador de `(&K, &V)` | `m.iter()` |
| `iter_mut()` | Iterador de `(&K, &mut V)` | `m.iter_mut()` |
| `drain()` | Remove e itera sobre todos os pares | `m.drain()` |
| `retain(f)` | Mantém pares onde `f` retorna `true` | `m.retain(\|k, v\| *v > 0)` |
| `extend(iter)` | Insere pares de um iterador | `m.extend([("b", 2)])` |
| `clear()` | Remove todos os elementos | `m.clear()` |

---

## Exemplos Práticos

### 1. A Entry API: Inserção Condicional

A Entry API é um dos recursos mais poderosos do `HashMap`. Ela permite verificar se uma chave existe e agir de acordo, tudo em uma única operação eficiente.

```rust
use std::collections::HashMap;

fn main() {
    let mut estoque: HashMap<&str, u32> = HashMap::new();

    // or_insert: insere o valor se a chave não existir
    estoque.entry("maçã").or_insert(0);
    estoque.entry("banana").or_insert(10);

    // or_insert_with: insere usando uma closure (avaliação preguiçosa)
    estoque.entry("laranja").or_insert_with(|| {
        println!("Calculando estoque inicial...");
        calcular_estoque_padrao()
    });

    // and_modify + or_insert: modifica se existir, insere se não
    let frutas = vec!["maçã", "banana", "maçã", "maçã", "banana", "laranja"];
    for fruta in frutas {
        estoque.entry(fruta)
            .and_modify(|qtd| *qtd += 1)
            .or_insert(1);
    }

    for (fruta, qtd) in &estoque {
        println!("{fruta}: {qtd}");
    }
}

fn calcular_estoque_padrao() -> u32 {
    5
}
```

### 2. Contando Ocorrências de Palavras

```rust
use std::collections::HashMap;

fn contar_palavras(texto: &str) -> HashMap<String, usize> {
    let mut contagem = HashMap::new();

    for palavra in texto.split_whitespace() {
        let normalizada = palavra
            .to_lowercase()
            .trim_matches(|c: char| !c.is_alphanumeric())
            .to_string();

        if !normalizada.is_empty() {
            *contagem.entry(normalizada).or_insert(0) += 1;
        }
    }

    contagem
}

fn main() {
    let texto = "Rust é rápido. Rust é seguro. Rust é produtivo!";
    let contagem = contar_palavras(texto);

    // Ordenar por frequência (decrescente)
    let mut pares: Vec<_> = contagem.iter().collect();
    pares.sort_by(|a, b| b.1.cmp(a.1));

    for (palavra, qtd) in pares {
        println!("{palavra}: {qtd}");
    }
}
```

### 3. Agrupando Dados por Categoria

```rust
use std::collections::HashMap;

#[derive(Debug)]
struct Produto {
    nome: String,
    categoria: String,
    preco: f64,
}

fn main() {
    let produtos = vec![
        Produto { nome: "Arroz".into(), categoria: "Alimentos".into(), preco: 5.99 },
        Produto { nome: "Feijão".into(), categoria: "Alimentos".into(), preco: 8.49 },
        Produto { nome: "Sabão".into(), categoria: "Limpeza".into(), preco: 3.29 },
        Produto { nome: "Detergente".into(), categoria: "Limpeza".into(), preco: 2.19 },
        Produto { nome: "Café".into(), categoria: "Alimentos".into(), preco: 12.90 },
    ];

    // Agrupar por categoria
    let mut por_categoria: HashMap<&str, Vec<&Produto>> = HashMap::new();
    for produto in &produtos {
        por_categoria
            .entry(&produto.categoria)
            .or_insert_with(Vec::new)
            .push(produto);
    }

    // Exibir agrupamentos com total
    for (categoria, lista) in &por_categoria {
        let total: f64 = lista.iter().map(|p| p.preco).sum();
        println!("\n{categoria} (total: R$ {total:.2}):");
        for p in lista {
            println!("  - {} (R$ {:.2})", p.nome, p.preco);
        }
    }
}
```

### 4. Cache Simples (Memoização)

```rust
use std::collections::HashMap;

fn fibonacci_memo(n: u64, cache: &mut HashMap<u64, u64>) -> u64 {
    if n <= 1 {
        return n;
    }

    if let Some(&resultado) = cache.get(&n) {
        return resultado;
    }

    let resultado = fibonacci_memo(n - 1, cache) + fibonacci_memo(n - 2, cache);
    cache.insert(n, resultado);
    resultado
}

fn main() {
    let mut cache = HashMap::new();

    for n in [10, 20, 30, 40, 50] {
        let resultado = fibonacci_memo(n, &mut cache);
        println!("fib({n}) = {resultado}");
    }

    println!("Entradas no cache: {}", cache.len());
}
```

### 5. Mesclando Dois HashMaps

```rust
use std::collections::HashMap;

fn mesclar(
    base: &mut HashMap<String, i32>,
    outro: HashMap<String, i32>,
    conflito: impl Fn(i32, i32) -> i32,
) {
    for (chave, valor_novo) in outro {
        base.entry(chave)
            .and_modify(|existente| *existente = conflito(*existente, valor_novo))
            .or_insert(valor_novo);
    }
}

fn main() {
    let mut vendas_jan = HashMap::from([
        ("Ana".into(), 150),
        ("Bruno".into(), 200),
        ("Carlos".into(), 100),
    ]);

    let vendas_fev = HashMap::from([
        ("Ana".into(), 180),
        ("Bruno".into(), 160),
        ("Diana".into(), 220),
    ]);

    // Somar vendas dos dois meses
    mesclar(&mut vendas_jan, vendas_fev, |a, b| a + b);

    for (nome, total) in &vendas_jan {
        println!("{nome}: {total}");
    }
    // Ana: 330, Bruno: 360, Carlos: 100, Diana: 220
}
```

---

## Dicas de Performance e Armadilhas

1. **Ordem não garantida**: A iteração sobre um `HashMap` não segue nenhuma ordem específica. Se precisar de ordem, use `BTreeMap` (ordenado por chave) ou colete em um `Vec` e ordene.

2. **Use `with_capacity`**: Se souber o número aproximado de entradas, `HashMap::with_capacity(n)` evita rehashing, que é uma operação custosa.

3. **Prefira `entry()` a `get()` + `insert()`**: A Entry API evita buscas duplicadas na tabela hash. Em vez de verificar com `contains_key` e depois inserir, use `entry().or_insert()`.

4. **Chaves `String` vs `&str`**: Se as chaves são literais conhecidos em compilação, use `&str` para evitar alocações. Se são dinâmicos, use `String`.

5. **Hasher personalizado**: O hasher padrão (`SipHash`) é resistente a ataques DoS mas não é o mais rápido. Para dados não controlados por usuários, considere crates como `ahash` ou `rustc-hash` para melhor performance.

6. **Cuidado com `[]` para acesso**: `mapa["chave"]` causa **panic** se a chave não existir. Prefira `mapa.get("chave")` que retorna `Option<&V>`.

---

## Veja Também

- [Usar HashMap em Rust](/receitas/usar-hashmap/) — receitas práticas com HashMap
- [Vec\<T\>: Vetor Dinâmico](/stdlib/vec/) — para coleções ordenadas por índice
- [String e &str](/stdlib/string/) — frequentemente usado como chave de HashMap
- [Iterator Trait](/stdlib/iterator/) — para transformar e processar pares chave-valor
- [Option\<T\>](/stdlib/option/) — retornado por `get()` e outros métodos
- [Cheatsheet Rust](/cheatsheet/) — referência rápida de sintaxe
- [Documentação oficial — std::collections::HashMap](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
