Introdução: a pergunta eterna do Stack Overflow
\n\nSe você já pesquisou "Declare a constant array in Go" no Google, provavelmente viu aquele tópico no Stack Overflow com milhares de visualizações. E sim, você não está sozinho na sua confusão. Em Go, realmente não se pode simplesmente escrever const arr = [...]int{1, 2, 3} — o compilador lhe dirá um educado "não".
Por que isso? E como fazer então, se precisamos de uma lista imutável de dados? Neste artigo, vamos entender a natureza das constantes em Go, descobrir por que arrays não podem ser constantes e encontrar as melhores soluções alternativas. Spoiler: a solução existe, e é até mais elegante do que você imagina.
\n\nPor que o Go não permite declarar um array constante?
\n\nPara entender isso, precisamos olhar sob o capô da linguagem. Em Go, constantes são valores imutáveis, calculados em tempo de compilação. Elas devem ser estritamente tipadas e conhecidas antes da execução do programa. Arrays, por outro lado, são tipos de dados compostos que ocupam memória e podem ser modificados.
\n\nAqui está um exemplo simples que NÃO compilará:
\n\npackage main\n\nconst arr = [3]int{1, 2, 3} // Erro: const initializer [3]int{1, 2, 3} is not a constant\n\nfunc main() {\n fmt.Println(arr)\n}\n\nO compilador diz: "Ei, isso não é uma constante!". E ele está certo. Mesmo que o array seja declarado como const, o Go não garante que seu conteúdo não será alterado através de ponteiros ou slices. Por isso, os desenvolvedores da linguagem decidiram: nada de arrays constantes.
Mas não se apresse em se decepcionar. Existem pelo menos três maneiras de contornar essa limitação, e cada uma tem suas vantagens.
\n\nMétodo 1: Usar uma variável com comentário "não mexer"
\n\nA maneira mais simples e ingênua é apenas declarar uma variável e torcer para que ninguém a altere. Mas somos desenvolvedores sérios, certo?
\n\npackage main\n\nimport "fmt"\n\n// arr - array constante. Por favor, não o altere.\nvar arr = [3]int{1, 2, 3}\n\nfunc main() {\n fmt.Println(arr)\n // arr[0] = 100 // Descomente — e tudo quebrará\n}\n\nAs desvantagens são óbvias: isso não é uma constante real. Qualquer um pode alterar o array através de uma atribuição. Mas para protótipos rápidos ou projetos pequenos, serve.
\n\nMétodo 2: Função getter (o caminho correto)
\n\nEsta abordagem é usada em código de produção. Escondemos o array dentro de uma função e retornamos uma cópia dele. Assim, ninguém conseguirá alterar o original.
\n\npackage main\n\nimport "fmt"\n\n// getColors retorna uma cópia do array de cores.\n// O array está protegido contra alterações externas.\nfunc getColors() [3]string {\n return [3]string{"Red", "Green", "Blue"}\n}\n\nfunc main() {\n colors := getColors()\n fmt.Println(colors)\n // colors[0] = "Yellow" // Isso alterará a cópia, não o original\n}\n\nPor que isso é bom? Porque:
\n- \n
- O array não pode ser alterado externamente — a função retorna uma cópia. \n
- O código é legível e compreensível. \n
- Fácil de testar e manter. \n
Mas há uma ressalva: cada chamada da função cria uma nova cópia do array. Se o array for grande (por exemplo, 1000 elementos), isso pode ser custoso. Nesse caso, use o próximo método.
\n\nMétodo 3: Variável de pacote com acesso privado
\n\nSe você está escrevendo um pacote e quer proteger o array contra alterações, torne-o não exportável (com letra minúscula) e forneça acesso através de uma função.
\n\npackage constants\n\n// Array acessível apenas dentro do pacote\nvar defaultPorts = [5]int{80, 443, 8080, 3000, 5000}\n\n// GetDefaultPorts retorna uma cópia do array de portas.\nfunc GetDefaultPorts() [5]int {\n return defaultPorts\n}\n\nAgora, os usuários do seu pacote podem apenas ler os dados, mas não alterá-los. Ideal para bibliotecas.
\n\nMétodo 4: Uso de iota para conjuntos constantes
\n\nE se você precisar não dos valores em si, mas de seus índices? Por exem