Rust Admin

O que Todo Dev Deve Saber sobre HashMap e HashSet em Rust: Estruturas de Dados por Chave Já leu

HashMap: Armazenamento Eficiente com Chaves HashMap é uma estrutura de dados que associa chaves a valores, permitindo busca, inserção e remoção em tempo O(1) médio. Em Rust, é implementado através de tabela hash com tratamento de colisões. Diferentemente de arrays, você não precisa de índices sequenciais — qualquer tipo que implemente e pode ser chave. Operações Essenciais O método é crucial para operações complexas. Ele oferece acesso otimizado quando você precisa verificar e modificar em uma única operação, evitando buscas redundantes. Use para definir um valor padrão se a chave não existir. HashSet: Conjuntos Únicos e Rápidos é uma coleção que garante unicidade de elementos e oferece operações de conjunto eficientes. Internamente, utiliza HashMap armazenando valores como chaves com valores vazios. Use HashSet quando precisar verificar pertencimento rapidamente ou eliminar duplicatas. Operações de Conjunto HashSet implementa operações matemáticas de conjuntos. As operações , e retornam iteradores, permitindo encadeamento eficiente. Use essas operações para resolver problemas de filtragem e análise de

HashMap: Armazenamento Eficiente com Chaves

HashMap é uma estrutura de dados que associa chaves a valores, permitindo busca, inserção e remoção em tempo O(1) médio. Em Rust, HashMap é implementado através de tabela hash com tratamento de colisões. Diferentemente de arrays, você não precisa de índices sequenciais — qualquer tipo que implemente Hash e Eq pode ser chave.

use std::collections::HashMap;

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

    // Inserção
    scores.insert("Alice", 95);
    scores.insert("Bob", 87);
    scores.insert("Charlie", 92);

    // Acesso
    match scores.get("Alice") {
        Some(score) => println!("Alice: {}", score),
        None => println!("Não encontrado"),
    }

    // Iteração
    for (name, score) in &scores {
        println!("{}: {}", name, score);
    }

    // Atualização
    scores.insert("Alice", 98);

    // Remoção
    scores.remove("Bob");

    println!("Total de alunos: {}", scores.len());
}

Operações Essenciais

O método entry() é crucial para operações complexas. Ele oferece acesso otimizado quando você precisa verificar e modificar em uma única operação, evitando buscas redundantes. Use or_insert() para definir um valor padrão se a chave não existir.

use std::collections::HashMap;

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

    // Contar frequência de palavras
    let text = vec!["rust", "rust", "java", "rust", "python", "java"];

    for word in text {
        *words.entry(word).or_insert(0) += 1;
    }

    for (word, count) in words {
        println!("{}: {} vezes", word, count);
    }
}

HashSet: Conjuntos Únicos e Rápidos

HashSet é uma coleção que garante unicidade de elementos e oferece operações de conjunto eficientes. Internamente, utiliza HashMap armazenando valores como chaves com valores vazios. Use HashSet quando precisar verificar pertencimento rapidamente ou eliminar duplicatas.

use std::collections::HashSet;

fn main() {
    let mut tags = HashSet::new();

    // Inserção (duplicatas são ignoradas)
    tags.insert("rust");
    tags.insert("programming");
    tags.insert("rust"); // Ignorado
    tags.insert("performance");

    // Verificação de pertencimento
    if tags.contains("rust") {
        println!("Tag 'rust' existe!");
    }

    // Remoção
    tags.remove("programming");

    println!("Total de tags: {}", tags.len());
}

Operações de Conjunto

HashSet implementa operações matemáticas de conjuntos. As operações union(), intersection() e difference() retornam iteradores, permitindo encadeamento eficiente. Use essas operações para resolver problemas de filtragem e análise de dados.

use std::collections::HashSet;

fn main() {
    let mut grupo_a: HashSet<&str> = ["alice", "bob", "charlie"].iter().cloned().collect();
    let mut grupo_b: HashSet<&str> = ["bob", "charlie", "diana"].iter().cloned().collect();

    // União
    let union: HashSet<_> = grupo_a.union(&grupo_b).cloned().collect();
    println!("União: {:?}", union);

    // Interseção
    let intersection: HashSet<_> = grupo_a.intersection(&grupo_b).cloned().collect();
    println!("Interseção: {:?}", intersection);

    // Diferença (em A mas não em B)
    let difference: HashSet<_> = grupo_a.difference(&grupo_b).cloned().collect();
    println!("Diferença: {:?}", difference);
}

Boas Práticas e Considerações de Performance

A escolha entre HashMap e HashSet depende do caso de uso. Use HashMap quando precisar associar dados a chaves; use HashSet para verificação rápida de pertencimento e operações de conjunto. Ambas exigem que as chaves implementem Hash e Eq. Para tipos customizados, implemente essas traits ou use #[derive(Hash, Eq, PartialEq)].

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

#[derive(Hash, Eq, PartialEq, Clone, Debug)]
struct Usuario {
    id: u32,
    nome: String,
}

fn main() {
    let mut usuarios_map: HashMap<u32, Usuario> = HashMap::new();
    let mut usuarios_set: HashSet<Usuario> = HashSet::new();

    let user = Usuario { id: 1, nome: "Alice".to_string() };
    usuarios_map.insert(1, user.clone());
    usuarios_set.insert(user);

    // Evite rehashing desnecessário
    let mut map_com_capacidade = HashMap::with_capacity(100);
    map_com_capacidade.insert(1, "valor");
}

Tratamento de Colisões e Segurança

Rust usa SipHash por padrão para resistir a ataques de negação de serviço baseados em colisões intencionais. Não mude o hasher sem motivo específico. Para tipos customizados, implemente a trait Hash corretamente: todos os campos relevantes para igualdade devem ser incluídos no hash.

Conclusão

HashMap e HashSet são estruturas fundamentais em Rust para operações rápidas com chaves. Primeiro: HashMap fornece associação eficiente chave-valor com O(1) médio; use entry() para operações complexas evitando buscas redundantes. Segundo: HashSet garante unicidade e oferece operações matemáticas poderosas como união e interseção. Terceiro: implemente corretamente Hash e Eq para tipos customizados e aproveite with_capacity() para otimizar alocações em casos com tamanho previsível.

Referências


Artigos relacionados