O que é Constant em Go?

Uma constant (constante) em Go é um valor imutável definido em tempo de compilação usando a palavra-chave const. Diferente de uma variável, uma constante não pode ser modificada após sua declaração — qualquer tentativa de alteração resulta em erro de compilação.

Constantes são fundamentais na linguagem Go porque garantem segurança e previsibilidade no código. Elas permitem que o compilador otimize o programa, substituindo referências a constantes diretamente pelos seus valores durante a compilação, eliminando qualquer overhead em tempo de execução.

Em Go, constantes podem representar valores numéricos (inteiros, ponto flutuante, complexos), strings, booleanos e runes. Diferente de muitas outras linguagens, Go possui um sistema de constantes extremamente poderoso, com suporte a constantes não tipadas que mantêm precisão arbitrária durante a avaliação de expressões em tempo de compilação.

Declarando constantes em Go

Constante simples

A forma mais básica de declarar uma constante usa a palavra-chave const:

const pi = 3.14159265358979323846
const saudacao = "Olá, mundo!"
const ativo = true

Constante tipada vs não tipada

Go diferencia entre constantes tipadas e não tipadas, e essa distinção é uma das características mais elegantes da linguagem:

// Constante não tipada — flexível, pode ser usada em diferentes contextos
const valor = 42

// Constante tipada — restrita ao tipo declarado
const limite int64 = 1000000

func exemplo() {
    var x int32 = valor   // OK: constante não tipada se adapta
    var y float64 = valor // OK: mesma constante funciona como float64

    // var z int32 = limite // ERRO: limite é int64, não int32
    _ = x
    _ = y
}

Constantes não tipadas são chamadas de “ideal constants” na especificação do Go. Elas têm precisão arbitrária e só recebem um tipo concreto quando são atribuídas a uma variável ou usadas em um contexto que exige um tipo específico.

Bloco de constantes

Quando você precisa declarar múltiplas constantes relacionadas, use um bloco const:

const (
    appNome    = "Golang Brasil"
    appVersao  = "2.1.0"
    appPorta   = 8080
    appTimeout = 30
)

Essa abordagem organiza o código e deixa claro que as constantes pertencem ao mesmo grupo lógico — algo muito comum em packages bem estruturados.

O poder do iota

Enumerações com iota

O iota é o mecanismo de Go para criar sequências enumeradas automaticamente dentro de blocos const. Ele começa em 0 e é incrementado a cada linha:

const (
    Domingo = iota // 0
    Segunda        // 1
    Terca          // 2
    Quarta         // 3
    Quinta         // 4
    Sexta          // 5
    Sabado         // 6
)

iota com expressões

O verdadeiro poder do iota aparece quando combinado com expressões:

// Unidades de armazenamento usando bit shifting
const (
    _  = iota             // descarta o valor 0
    KB = 1 << (10 * iota) // 1 << 10 = 1024
    MB                    // 1 << 20 = 1048576
    GB                    // 1 << 30 = 1073741824
    TB                    // 1 << 40
    PB                    // 1 << 50
)

func main() {
    tamanhoArquivo := 2.5 * float64(GB)
    fmt.Printf("Tamanho: %.2f GB\n", tamanhoArquivo/float64(GB))
}

iota com bitmask (flags)

Um padrão extremamente útil para flags e permissões:

const (
    Leitura   = 1 << iota // 1 (001)
    Escrita               // 2 (010)
    Execucao              // 4 (100)
)

func temPermissao(permissoes, flag int) bool {
    return permissoes&flag != 0
}

func main() {
    minhasPermissoes := Leitura | Escrita // 3 (011)

    fmt.Println(temPermissao(minhasPermissoes, Leitura))  // true
    fmt.Println(temPermissao(minhasPermissoes, Execucao)) // false
}

Esse padrão é amplamente utilizado na standard library, por exemplo em os.FileMode, e é essencial quando você trabalha com interfaces que definem comportamentos baseados em flags.

iota reinicia em cada bloco const

Um detalhe importante: iota reinicia em 0 a cada novo bloco const:

const (
    A = iota // 0
    B        // 1
)

const (
    C = iota // 0 — reiniciou!
    D        // 1
)

Constantes e tipos customizados

Um padrão idiomático em Go é combinar constantes com tipos customizados para criar enumerações seguras:

type Status int

const (
    Pendente  Status = iota
    Aprovado
    Rejeitado
    Cancelado
)

func (s Status) String() string {
    nomes := [...]string{"Pendente", "Aprovado", "Rejeitado", "Cancelado"}
    if s < Pendente || s > Cancelado {
        return "Desconhecido"
    }
    return nomes[s]
}

func processarPedido(status Status) {
    switch status {
    case Pendente:
        fmt.Println("Aguardando aprovação...")
    case Aprovado:
        fmt.Println("Pedido aprovado!")
    case Rejeitado:
        fmt.Println("Pedido rejeitado.")
    case Cancelado:
        fmt.Println("Pedido cancelado.")
    }
}

Essa abordagem é preferível a usar int ou string diretamente porque o compilador pode verificar atribuições inválidas. É o padrão recomendado em projetos profissionais e em APIs REST.

Precisão de constantes numéricas

Uma das características mais impressionantes do sistema de constantes em Go é a precisão arbitrária para constantes não tipadas:

const (
    // Precisão muito maior que float64
    precisao = 3.14159265358979323846264338327950288419716939937510

    // Aritimética com precisão total em tempo de compilação
    resultado = precisao * precisao // calculado com precisão completa
)

func main() {
    // Só perde precisão quando atribuído a uma variável
    var f float64 = resultado
    fmt.Println(f) // arredondado para precisão de float64
}

Isso significa que expressões com constantes são avaliadas com precisão arbitrária pelo compilador, e o arredondamento só acontece quando o valor é atribuído a uma variável com tipo concreto.

Constantes vs variáveis: quando usar cada uma

A regra é simples: use constantes sempre que o valor não precisa mudar durante a execução do programa.

// Use const para valores fixos
const (
    maxTentativas = 3
    timeoutPadrao = 30 // segundos
    versaoAPI     = "v2"
)

// Use var para valores que mudam
var (
    contadorRequests int
    ultimoErro       error
    conexaoAtiva     bool
)

Benefícios de usar constantes:

  1. Segurança: o compilador impede modificações acidentais
  2. Performance: valores substituídos diretamente no código compilado
  3. Documentação: indica claramente a intenção de imutabilidade
  4. Otimização: permite ao compilador fazer inlining automático

Para entender melhor o uso de variáveis e quando cada abordagem é mais adequada, compare os exemplos acima e considere o contexto do seu projeto.

O que NÃO pode ser constante em Go

Nem tudo pode ser declarado como constante em Go. Apenas tipos básicos são permitidos:

// Funciona: tipos básicos
const nome = "Go"
const idade = 15
const ativo = true

// NÃO funciona: tipos compostos
// const lista = []int{1, 2, 3}        // ERRO
// const mapa = map[string]int{}       // ERRO
// const pessoa = Pessoa{Nome: "Ana"}  // ERRO

Se você precisa de valores imutáveis com tipos compostos, o padrão é usar variáveis de package com nomes que indicam imutabilidade, ou encapsular em funcs que retornam novos valores a cada chamada.

Constantes em projetos reais

Configuração de aplicação

package config

const (
    DefaultPort    = 8080
    DefaultHost    = "localhost"
    MaxConnections = 100
    ReadTimeout    = 15 // segundos
    WriteTimeout   = 15 // segundos
)

Códigos de erro

type ErrCode int

const (
    ErrNotFound      ErrCode = 404
    ErrUnauthorized  ErrCode = 401
    ErrInternalError ErrCode = 500
    ErrBadRequest    ErrCode = 400
)

Mensagens e templates

const (
    MsgBoasVindas = "Bem-vindo ao sistema"
    MsgErroLogin  = "Credenciais inválidas"
    MsgSucesso    = "Operação realizada com sucesso"
)

Esses padrões são essenciais ao construir microsserviços e aplicações backend robustas com tratamento adequado de erros.

Boas práticas com constantes

  1. Use nomes descritivos: maxRetries é melhor que mr
  2. Agrupe constantes relacionadas em blocos const
  3. Prefira constantes não tipadas quando a flexibilidade é necessária
  4. Use iota para enumerações — mais legível e menos propenso a erros
  5. Exporte apenas o necessário: constantes internas devem ser minúsculas
  6. Documente valores não óbvios: explique por que o valor é aquele

Para mais fundamentos da linguagem, explore o glossário completo e os tutoriais de Go para iniciantes.

Perguntas frequentes (FAQ)

Qual a diferença entre const e var em Go?

const define valores imutáveis conhecidos em tempo de compilação, enquanto var define variáveis que podem mudar durante a execução. Constantes são substituídas diretamente no código compilado, eliminando overhead de acesso à memória. Use const sempre que o valor não precisar mudar — garante segurança e melhor performance.

Como funciona o iota em Go?

O iota é um identificador especial usado dentro de blocos const que começa em 0 e incrementa automaticamente a cada nova constante no bloco. Pode ser combinado com expressões (como 1 << iota para bitmasks) e reinicia em 0 em cada novo bloco const. É a forma idiomática de criar enumerações em Go.

Posso criar constantes com structs ou slices em Go?

Não. Em Go, apenas tipos básicos podem ser constantes: números (inteiros, float, complexos), strings, booleanos e runes. Tipos compostos como structs, slices, maps e arrays não podem ser constantes. Para valores compostos imutáveis, use variáveis de package não exportadas ou funções construtoras.

Quando usar constantes tipadas vs não tipadas?

Use constantes não tipadas (sem tipo explícito) quando quiser flexibilidade — elas se adaptam ao contexto de uso. Use constantes tipadas quando quiser restringir o uso a um tipo específico, como em enumerações com type Status int. Constantes não tipadas mantêm precisão arbitrária durante a compilação, o que é útil para cálculos numéricos precisos.