Os tipos básicos do Go são números, booleanos e strings. Toda variável tem exatamente um tipo, fixado em tempo de compilação, e o Go nunca converte entre tipos por você. %T imprime o tipo de qualquer valor:
Repare que 'G' é impresso como 71, com tipo int32: um caractere entre aspas simples é uma rune, que é um número (o code point Unicode). rune é um alias de int32 (o mesmo tipo com um segundo nome), então %T mostra int32. Do mesmo jeito, byte aparece como uint8.
Inteiros
| Tipo | Tamanho | Faixa |
|---|---|---|
int8 | 8 bits | -128 a 127 |
int16 | 16 bits | -32.768 a 32.767 |
int32 | 32 bits | cerca de -2,1 bilhões a 2,1 bilhões |
int64 | 64 bits | cerca de -9,2 quintilhões a 9,2 quintilhões |
uint8 (byte) | 8 bits | 0 a 255 |
uint16 | 16 bits | 0 a 65.535 |
uint32 | 32 bits | 0 a cerca de 4,3 bilhões |
uint64 | 64 bits | 0 a cerca de 18,4 quintilhões |
int, uint | 32 ou 64 bits | tamanho da palavra da plataforma |
uintptr | tamanho da plataforma | guarda o valor de um ponteiro, para código de baixo nível |
Use int por padrão. len() devolve int, índices de slice são int e contadores de laço são int. Em toda plataforma de 64 bits, int tem 64 bits. Recorra aos tipos com tamanho quando o tamanho fizer parte de um contrato: int32 em um formato de arquivo binário, uint8 para bytes brutos, int64 para um timestamp Unix em nanossegundos.
Evite tipos sem sinal para quantidades que "não podem ser negativas", como contagens. Subtrair além de zero dá a volta para um número enorme, em vez de gerar um negativo que você conseguiria detectar.
Limites e overflow
O pacote math tem uma constante para cada limite. Em tempo de execução, uma conta inteira que estoura dá a volta em silêncio:
Sem panic, sem erro: 127 + 1 vira -128. Só expressões constantes são verificadas em tempo de compilação (var b int8 = 128 não compila). Se overflow for possível com os seus dados, verifique antes da operação ou use math/big.
Literais inteiros
million := 1_000_000 // underscores for readability (Go 1.13+)
mask := 0xFF // hexadecimal
perm := 0o755 // octal (also the older form 0755)
flags := 0b1010 // binary
Números de ponto flutuante
| Tipo | Tamanho | Precisão |
|---|---|---|
float32 | 32 bits | cerca de 6 a 9 dígitos significativos |
float64 | 64 bits | cerca de 15 a 17 dígitos significativos |
Um literal com ponto decimal ou expoente (2.5, 1e6) é float64 por padrão, e o pacote math recebe e devolve float64. Use esse tipo, a menos que a memória de um array grande importe.
Floats são binários, então a maioria das frações decimais é uma aproximação:
Daí saem duas regras. Nunca compare floats com == depois de fazer contas. E nunca guarde dinheiro em float: use um número inteiro de centavos ou uma biblioteca decimal.
Dividir um float por zero dá +Inf, -Inf ou NaN em vez de panic. Dividir um inteiro por zero causa panic em tempo de execução (runtime error: integer divide by zero), e um divisor zero constante é erro de compilação.
Booleanos
bool guarda true ou false, e o valor zero é false. Go não trata números, strings vazias ou nil como booleanos. if count {} é erro de compilação; escreva if count > 0 {}. Os operadores são &&, || e !, e && e || fazem avaliação de curto-circuito.
Strings
Uma string é uma sequência imutável de bytes, normalmente texto UTF-8. len(s) conta bytes, não caracteres:
é ocupa dois bytes em UTF-8, então len mostra 6 para cinco caracteres. Strings entre aspas duplas processam escapes como \n; raw strings entre crases não processam, e podem ocupar várias linhas. A página de strings cobre o pacote strings, e a de runes e bytes aprofunda o UTF-8.
byte e rune
| Alias | Mesmo que | Guarda |
|---|---|---|
byte | uint8 | um byte de dado bruto |
rune | int32 | um code point Unicode |
São aliases, não tipos novos: um byte e um uint8 são intercambiáveis sem conversão. Os nomes dizem o que o número significa.
Números complexos
Go tem tipos complexos embutidos, complex64 e complex128, com real, imag e o pacote math/cmplx:
Poucos programas precisam deles, mas processamento de sinais e parte do código numérico precisam.
Tipos compostos e de referência
Os tipos básicos se combinam em tipos compostos. Cada um tem a sua página:
| Tipo | Exemplo | Valor zero |
|---|---|---|
| array | [3]int | três zeros |
| slice | []int | nil |
| map | map[string]int | nil |
| struct | struct{ X, Y int } | todos os campos zerados |
| ponteiro | *int | nil |
| função | func(int) int | nil |
| channel | chan int | nil |
| interface | error, any | nil |
any é um alias de interface{} (desde o Go 1.18) e pode guardar um valor de qualquer tipo.
Tipos nomeados
Você pode definir um tipo novo a partir de um existente. Ele tem a mesma representação, mas é um tipo distinto, e pode ter métodos:
type Celsius float64
type UserID int64
var t Celsius = 21.5
var f float64 = t // compile error: cannot use t (variable of float64 type Celsius) as float64 value in variable declaration
Essa rigidez é proposital: um UserID não pode ser passado por acidente onde se espera um OrderID. Converta explicitamente quando for essa a intenção: float64(t). Veja conversão de tipos para as regras e as funções de strconv para ir de números para strings e vice-versa.
Valores zero
Todo tipo tem um valor zero, que é o que a variável guarda antes de você atribuir algo: 0 para números, false para bool, "" para strings e nil para ponteiros, slices, maps, channels, funções e interfaces. Não existem variáveis não inicializadas em Go.
Perguntas frequentes
Qual o tamanho de um int em Go?
int e uint têm 64 bits em plataformas de 64 bits (amd64, arm64) e 32 bits em plataformas de 32 bits. Se você precisa de um tamanho fixo, para um formato de arquivo ou protocolo de rede, use int32, int64, uint8 e assim por diante. Para contadores, índices e tamanhos comuns, use int.
Como imprimir o tipo de uma variável em Go?
Use o verbo %T: fmt.Printf("%T\n", x) imprime int, float64, []string, main.User e assim por diante. No código, reflect.TypeOf(x) devolve a mesma informação como um valor que você pode inspecionar.
Qual a diferença entre byte e rune em Go?
byte é um alias de uint8 e guarda um byte de dado bruto. rune é um alias de int32 e guarda um code point Unicode. Uma string é uma sequência de bytes; percorrê-la com for range a decodifica em runes.
Devo usar float32 ou float64 em Go?
Use float64, a menos que tenha um motivo para não usar. É o tipo padrão dos literais de ponto flutuante, o tipo com que o pacote math trabalha, e tem cerca de 15 a 17 dígitos decimais significativos de precisão, contra cerca de 6 a 9 do float32. Escolha float32 só para reduzir pela metade a memória de arrays grandes ou para bater com um formato externo.
Qual o valor máximo de um int em Go?
Use as constantes do pacote math: math.MaxInt (9223372036854775807 em plataformas de 64 bits), math.MinInt, math.MaxInt64, math.MaxUint32 e assim por diante. Uma conta que passa do limite dá a volta em silêncio em tempo de execução; ela não causa panic.