Menu

const em Golang: constantes tipadas e não tipadas explicadas

Como const funciona em Go: declarar constantes, a diferença entre constantes tipadas e não tipadas, expressões constantes com precisão arbitrária e por que Go não tem slices, maps ou structs constantes.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Uma constante é um valor fixado em tempo de compilação. Declare com const, e o Go recusa qualquer tentativa de alterá-la.

Constantes podem ser declaradas no nível de pacote ou dentro de uma função, uma por linha ou agrupadas em um bloco const ( ... ). MB e GB são calculadas a partir de outras constantes, e o compilador faz essa conta uma vez só, no build.

Atribuir a uma constante, como em MaxRetries = 5, é erro de compilação:

./main.go:8:2: cannot assign to MaxRetries (neither addressable nor a map index expression)

O que pode ser uma constante

Só três tipos de valores: booleanos, números (inteiros, floats, números complexos e runes) e strings. O valor precisa ser calculável pelo compilador, ou seja, literais, outras constantes, aritmética entre eles e algumas funções embutidas, como len de uma string constante.

Tudo o que exige executar código ou alocar memória fica de fora:

const Colors = []string{"red", "green"} // slice
const Started = time.Now()              // function call
./main.go:9:16: []string{…} (value of type []string) is not constant
./main.go:10:13: time.Now() (value of struct type time.Time) is not constant

Por que Go não tem slices ou maps constantes

Slices, maps e structs que os contêm são referências a memória que existe em tempo de execução, então o compilador não consegue embuti-los no programa como valores fixos, e Go não tem modificador readonly ou final para variáveis. As alternativas comuns:

A cópia custa uma alocação por chamada, o que não é problema para dados do tamanho de uma configuração. Para buscas por chave, um switch dentro de uma função é outra opção com cara de constante: func statusText(code int) string { switch code { ... } }.

Constantes não tipadas

Uma constante declarada sem tipo é não tipada (untyped). Ela tem uma categoria (inteiro, float, rune, string, bool), mas nenhum tipo Go específico até ser usada, e se adapta ao contexto:

Ratio funciona como int, float64, uint8 e float32 sem conversão. É por isso que time.Sleep(2 * time.Second) compila: 2 é não tipado e vira um time.Duration.

Quando o contexto não exige um tipo, como em x := Ratio, a constante recebe o seu tipo padrão:

Categoria da constante não tipadaTipo padrão
inteiro (42)int
ponto flutuante (4.2)float64
rune ('a')rune (int32)
complexo (2i)complex128
stringstring
booleanobool

Aritmética exata

Constantes numéricas não tipadas são exatas. O compilador representa inteiros com pelo menos 256 bits, então valores intermediários podem ser muito maiores do que qualquer tipo Go:

Huge em si não pode ser impresso como inteiro, porque passá-lo para fmt.Println o converte para int, e o compilador percebe isso (float64(Huge) funciona, já que um float comporta essa magnitude):

cannot use Huge (untyped int constant 1267650600228229401496703205376) as int value in argument to fmt.Println (overflows)

A mesma verificação barra erros menores em tempo de compilação, como var b byte = 300:

cannot use 300 (untyped int constant) as byte value in variable declaration (overflows)

Constantes tipadas

Dê um tipo a uma constante e ela passa a se comportar como um valor desse tipo em todo lugar, inclusive na recusa do Go em misturar tipos:

const Limit int = 10

var f float64 = 2
fmt.Println(Limit * f)
invalid operation: Limit * f (mismatched types int and float64)

Com const Limit = 10 (não tipada), Limit * f compila e dá 20. Então deixe as constantes não tipadas, a menos que o tipo tenha significado. Ele tem quando você declara constantes de um tipo nomeado seu, que é como Go constrói enums:

type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
)

Aqui o tipo é o objetivo: uma função que recebe um Weekday documenta o que espera. iota e os padrões de enum construídos com ele estão na página de enums e iota.

const ou var

constvar
Pode mudarnãosim
Valor conhecidoem tempo de compilaçãoem tempo de execução
Tipos permitidosbool, numéricos, stringqualquer um
Ocupa memória em tempo de execuçãonãosim
Dá para pegar o endereço (&x)nãosim
Sem uso é erronãosim, para locais

Use const para tudo o que é realmente fixo: limites, tamanhos, nomes, códigos de protocolo, strings de formato. Você ganha de graça verificação de overflow em tempo de compilação e aritmética exata.

Armadilhas

Constantes tipadas não se adaptam. const Timeout int = 5 não pode ser passada onde se espera um time.Duration sem conversão; uma const Timeout = 5 não tipada pode ser multiplicada: Timeout * time.Second.

Divisão inteira acontece em constantes inteiras. const Half = 1 / 2 vale 0, porque os dois operandos são inteiros não tipados. Escreva 1.0 / 2 para obter 0.5.

Sem endereço. &MaxRetries não compila. Se uma API pede um *int, copie a constante para uma variável antes.

Perguntas frequentes

Como declarar uma constante em Go?

Com const: const MaxRetries = 3 ou, com tipo explícito, const Timeout time.Duration = 5 * time.Second. Agrupe várias em um bloco: const ( A = 1; B = 2 ). O valor precisa ser calculável em tempo de compilação.

Dá para criar um slice, map ou array constante em Go?

Não. Constantes só podem ser booleanos, números (incluindo runes) e strings. const Colors = []string{"red"} falha com is not constant. Use um var de nível de pacote e, se quem chama não puder alterá-lo, exponha uma função que devolve uma cópia nova.

O que é uma constante não tipada em Go?

Uma constante declarada sem tipo, como const Pi = 3.14159. Ela não tem tipo fixo até ser usada, então a mesma constante funciona como float32, como float64 ou, se o valor permitir, como int. Constantes não tipadas também são exatas: o compilador mantém pelo menos 256 bits de precisão, então const Big = 1 << 100 é válido desde que você só a use em expressões cujo resultado caiba no tipo.

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

Uma const é fixada em tempo de compilação e nunca muda; não ocupa memória em tempo de execução e só pode guardar um bool, um número ou uma string. Uma var é uma posição de memória que pode receber novos valores e guardar qualquer tipo, inclusive valores calculados em tempo de execução, como time.Now().

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR