A eterna dor de cabeça do desenvolvedor Go: como extrair rapidamente todas as chaves de um map?
\nVocê já escreveu algo assim em Go?
\nm := map[string]int{"go": 1, "python": 2, "rust": 3}\nkeys := make([]string, 0, len(m))\nfor k := range m {\n keys = append(keys, k)\n}\n\nSe sim, você não está sozinho. Obter um slice de chaves de um map é uma das tarefas mais populares no Stack Overflow na categoria Go. A pergunta acumula milhares de visualizações e dezenas de respostas com abordagens diferentes. E não é surpresa: Go não tem uma função nativa keys() como Python ou JavaScript. Toda vez é preciso reinventar a roda.
Mas 2025 trouxe mudanças. Com o lançamento do Go 1.22 e os generics, além de novos idioms, surgiram soluções mais elegantes. Neste artigo, vamos analisar todas as formas de obter um slice de chaves de um map — desde o clássico até as melhores práticas modernas. Vamos nessa!
\n\nPor que Go não tem uma função keys() nativa?
\nAntes de mergulhar no código, vamos entender a filosofia da linguagem. Go é minimalista. Seus criadores deliberadamente não adicionam funções que podem ser implementadas em uma única linha. for k := range m é a forma nativa de iterar sobre um map. Mas o problema é que:
- \n
- A ordem das chaves não é garantida (e isso é uma feature, não um bug) \n
- Não há açúcar sintático para "coletar tudo em um slice" \n
- Generics só surgiram no 1.18 e se consolidaram no 1.22 \n
Por isso, a comunidade desenvolveu vários padrões. Vamos compará-los.
\n\nMétodo 1: Loop clássico (nível básico)
\nA forma mais simples e direta é a que mostramos no início. Funciona em qualquer versão do Go.
\nfunc Keys(m map[string]int) []string {\n keys := make([]string, 0, len(m))\n for k := range m {\n keys = append(keys, k)\n }\n return keys\n}\n\nVantagens:
\n- \n
- Transparência — qualquer iniciante entende o que está acontecendo \n
- Sem dependências da versão do Go \n
- Fácil de modificar (por exemplo, adicionar filtros) \n
Desvantagens:
\n- \n
- Muito código repetitivo para cada map \n
- É necessário escrever uma função separada para cada tipo \n
Veredito: ótimo para exemplos didáticos ou tarefas pontuais. Mas em código de produção, a gente busca universalidade.
\n\nMétodo 2: Generics (Go 1.18+)
\nCom a chegada dos generics, foi possível criar uma única função para qualquer tipo de chave.
\nfunc Keys[K comparable, V any](m map[K]V) []K {\n keys := make([]K, 0, len(m))\n for k := range m {\n keys = append(keys, k)\n }\n return keys\n}\n\n// Uso:\nm := map[string]int{"a": 1, "b": 2}\nkeys := Keys(m) // []string{"a", "b"}\n\nQue beleza, não? Uma função só e tudo funciona. Go 1.22 tornou os generics ainda mais estáveis, então este método é o recomendado para novos projetos.
\nImportante: as chaves precisam ser comparable. Isso é automaticamente verdade para todos os tipos padrão (string, int, float, struct sem slices, etc.).
Método 3: Usando reflect (para casos exóticos)
\nÀs vezes, é preciso trabalhar com um map cujo tipo só é conhecido em tempo de execução. É aí que o pacote reflect entra em cena.
func KeysReflect(m interface{}) []interface{} {\n v := reflect.ValueOf(m)\n if v.Kind() != reflect.Map {\n return nil\n }\n keys := make([]interface{}, v.Len())\n for i, k := range v.MapKeys() {\n keys[i] = k.Interface()\n }\n return keys\n}\n\nQuando usar:
\n- \n
- Ao serializar/desserializar estruturas desconhecidas \n
- Em bibliotecas de uso geral \n
- Quando o tipo do map vem de uma fonte externa (JSON, YAML)