Go nunca converte tipos implicitamente. Você converte entre tipos compatíveis com T(v), e entre números e texto com o pacote strconv. As duas conversões mais buscadas:
strconv.Itoa ("integer to ASCII") formata um int como texto decimal. strconv.Atoi ("ASCII to integer") interpreta um texto como int e devolve um erro quando o texto não é um número válido. Sempre verifique esse erro.
A conversão T(v)
A sintaxe de conversão do Go parece uma chamada de função com o nome do tipo de destino. Ela funciona em três situações:
- entre tipos numéricos (
int,int64,float64,uint8, ...), - entre
stringe[]byteou[]rune, - entre tipos que compartilham o tipo subjacente (
Celsiusefloat64).
Leia os resultados com atenção:
int(3.9)é3eint(-3.9)é-3. A conversão trunca em direção a zero; ela não arredonda. Use antesmath.Round,math.Flooroumath.Ceilpara escolher o comportamento.math.Roundarredonda a metade para longe do zero, então-3.5vira-4.uint8(300)é44, porque só sobram os 8 bits mais baixos (300 menos 256), eint8(200)é-56pelo mesmo motivo. Sem erro, sem panic.Celsiusefloat64compartilham o tipo subjacente, então convertem livremente, mas só de forma explícita.
Os valores estão em variáveis de propósito. Com constantes, as mesmas conversões não compilam.
Constantes são verificadas, variáveis não
Converter uma constante que não cabe no tipo é erro de compilação. Converter uma variável com o mesmo valor dá a volta em silêncio:
fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8
Converter uma constante não inteira para um tipo inteiro também é rejeitado, enquanto o mesmo valor em uma variável é truncado:
./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int
Se o valor float estiver fora da faixa do tipo inteiro de destino (por exemplo int64(1e20)), o resultado depende da implementação: amd64 e arm64, por exemplo, dão respostas diferentes. Confira a faixa antes de converter valores não confiáveis.
Convertendo números em strings
| De | Função | Exemplo | Resultado |
|---|---|---|---|
int | strconv.Itoa(n) | strconv.Itoa(-7) | "-7" |
int64 | strconv.FormatInt(n, base) | strconv.FormatInt(255, 16) | "ff" |
uint64 | strconv.FormatUint(n, base) | strconv.FormatUint(5, 2) | "101" |
float64 | strconv.FormatFloat(f, fmt, prec, 64) | strconv.FormatFloat(3.14159, 'f', 2, 64) | "3.14" |
bool | strconv.FormatBool(b) | strconv.FormatBool(true) | "true" |
| qualquer coisa | fmt.Sprint(v) | fmt.Sprint(3.5) | "3.5" |
| qualquer coisa, formatada | fmt.Sprintf(format, v) | fmt.Sprintf("%05d", 42) | "00042" |
FormatFloat recebe um byte de formato ('f' para notação fixa, 'e' para expoente, 'g' para o que for mais curto), uma precisão (-1 significa "o menor número de dígitos que volta exatamente ao mesmo valor") e o tamanho em bits do float original (64 ou 32).
strconv é mais rápido que fmt.Sprint, que empacota o valor em uma interface e passa pelo caminho de formatação genérico do fmt. Em um laço quente essa diferença aparece; para conversões ocasionais, escolha o que for mais legível.
Convertendo strings em números
| Para | Função | Devolve |
|---|---|---|
int | strconv.Atoi(s) | int, error |
| qualquer int com sinal | strconv.ParseInt(s, base, bitSize) | int64, error |
| qualquer int sem sinal | strconv.ParseUint(s, base, bitSize) | uint64, error |
| float | strconv.ParseFloat(s, bitSize) | float64, error |
| bool | strconv.ParseBool(s) | bool, error |
ParseInt sempre devolve um int64. O argumento bitSize (0, 8, 16, 32, 64) define a faixa aceita, então o resultado com certeza cabe quando você o converte para um tipo menor. base 0 significa "deduzir pelo prefixo", então 0x1f, 0o17, 0b101 e 1_000 são todos aceitos.
O que a saída mostra:
" 42"falha. OAtoiaceita um sinal opcional e dígitos, nada mais. Entradas lidas combufiocostumam terminar em\n, então remova isso."4.2"é inválido para oAtoi. UseParseFloatpara decimais.- Em um erro de faixa,
ParseIntdevolve o maior valor que cabe (127paraint8) junto com o erro. Não use o valor quando o erro não for nil. - Os erros são valores
*strconv.NumErrorque empacotamstrconv.ErrSyntaxoustrconv.ErrRange, entãoerrors.Isconsegue diferenciá-los.
ParseBool aceita 1, t, T, TRUE, true, True e as formas equivalentes de false. "yes" e "on" dão erro.
A armadilha do string(65)
Converter um inteiro para string não gera dígitos. Gera o caractere com aquele code point Unicode:
n := 65
s := string(n) // "A", not "65"
O compilador aceita, mas o go vet reporta:
./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits
Se você quer mesmo o caractere, deixe isso claro com uma rune: string(rune(n)). Se quer o número como texto, use strconv.Itoa(n). Converter uma rune ou um byte para string é normal e comum:
Strings, bytes e runes
string, []byte e []rune se convertem entre si com T(v). Cada conversão copia os dados, porque strings são imutáveis e slices não:
Converta para []rune quando precisar indexar ou modificar por caractere; converta para []byte para I/O, hashing e edições no nível de byte. A página de runes e bytes explica o UTF-8 em detalhes.
Conversão ou type assertion
Uma conversão muda um valor de um tipo concreto para outro. Tirar o valor concreto de dentro de uma interface (any, error, io.Reader) é outra operação, a type assertion:
var v any = 42
n := v.(int) // type assertion: v holds an int, give it to me
f := float64(n) // conversion: int to float64
// f := float64(v) // compile error: cannot convert v (variable of interface type any)
// // to type float64: need type assertion
Primeiro a assertion, depois a conversão. A forma vírgula-ok n, ok := v.(int) evita um panic quando o tipo está errado.
Referência rápida
| Tarefa | Código |
|---|---|
| int para string | strconv.Itoa(n) |
| int64 para string | strconv.FormatInt(n, 10) |
| string para int | n, err := strconv.Atoi(s) |
| string para int64 | n, err := strconv.ParseInt(s, 10, 64) |
| string para float64 | f, err := strconv.ParseFloat(s, 64) |
| float64 para string | strconv.FormatFloat(f, 'f', -1, 64) |
| float64 para int | int(f) (trunca) ou int(math.Round(f)) |
| int para float64 | float64(n) |
| string para []byte | []byte(s) |
| []byte para string | string(b) |
| rune para string | string(r) |
| bool para string | strconv.FormatBool(b) |
| qualquer valor para string | fmt.Sprint(v) |
Perguntas frequentes
Como converter um int para string em Go?
Use strconv.Itoa(n): strconv.Itoa(42) devolve "42". Para um int64 use strconv.FormatInt(n, 10). fmt.Sprint(n) também funciona com qualquer tipo, mas é mais lento. Não escreva string(n): isso trata n como um code point Unicode, então string(65) é "A".
Como converter uma string para int em Go?
Use strconv.Atoi, que devolve o número e um erro:
n, err := strconv.Atoi("42")
if err != nil {
// not a valid integer
}
Para um tamanho ou uma base específicos, use strconv.ParseInt(s, 10, 64), que devolve um int64. O Atoi não remove espaços, então " 42" dá erro; chame strings.TrimSpace antes.
Como fazer cast em Go?
Go chama isso de conversão, e a sintaxe é T(v): float64(n), int(f), []byte(s). Funciona entre tipos numéricos, entre strings e slices de bytes ou de runes, e entre tipos com o mesmo tipo subjacente. Ela não interpreta texto: transformar "42" em 42 exige strconv. Tirar um tipo concreto de dentro de uma interface é uma type assertion, v.(T), não uma conversão.
Como converter um float para int em Go?
int(f) trunca em direção a zero: int(3.9) é 3 e int(-3.9) é -3. Para arredondar, use int(math.Round(f)). Se o float estiver fora da faixa do tipo inteiro, o resultado depende da implementação, então confira a faixa antes quando o valor vier de uma entrada externa.
Por que string(65) devolve "A" em Go?
Converter um inteiro para string o interpreta como um code point Unicode, e 65 é o code point de A. O go vet aponta isso: conversion from int to string yields a string of one rune, not a string of digits. Use strconv.Itoa(65) para obter "65".