O pacote fmt tem três famílias de funções de impressão, e cada família tem as mesmas três variantes:
| Função | A saída vai para | Formato |
|---|---|---|
Print, Println, Printf | saída padrão | padrão, padrão com espaços e quebra de linha, string de formato |
Sprint, Sprintln, Sprintf | uma string devolvida | os mesmos três estilos |
Fprint, Fprintln, Fprintf | qualquer io.Writer (arquivo, buffer, resposta HTTP) | os mesmos três estilos |
Errorf | um error devolvido | string de formato, mais %w para empacotar |
Println coloca espaços entre os operandos e uma quebra de linha no final. Printf não acrescenta nada: você mesmo escreve o \n. Print só coloca espaço entre operandos que não são strings, o que surpreende o bastante para a maior parte do código usar Println ou Printf.
Verbos de formato
Gerais
| Verbo | Imprime | Exemplo de saída |
|---|---|---|
%v | o valor em um formato padrão | {Ana 31 [admin]} |
%+v | structs com os nomes dos campos | {Name:Ana Age:31 Tags:[admin]} |
%#v | sintaxe Go do valor | main.User{Name:"Ana", Age:31, Tags:[]string{"admin"}} |
%T | o tipo | main.User |
%% | um sinal de porcentagem literal | % |
%+v é o verbo para usar na depuração. Um ponteiro para struct é impresso como &{...} em vez de um endereço. Maps são impressos com as chaves ordenadas, então a saída é estável mesmo com a ordem de iteração dos maps sendo aleatória.
Inteiros
| Verbo | Significado | fmt.Sprintf(verb, 255) |
|---|---|---|
%d | decimal | 255 |
%b | binário | 11111111 |
%o | octal | 377 |
%O | octal com prefixo 0o | 0o377 |
%x / %X | hexadecimal, minúsculas ou maiúsculas | ff / FF |
%#x | hexadecimal com prefixo 0x | 0xff |
%c | o caractere com aquele code point | ÿ |
%q | um literal de caractere entre aspas | 'ÿ' |
%U | formato Unicode | U+00FF |
Floats
| Verbo | Significado | fmt.Sprintf(verb, 1234.5678) |
|---|---|---|
%f | decimal, 6 casas por padrão | 1234.567800 |
%.2f | decimal, 2 casas | 1234.57 |
%e | notação científica | 1.234568e+03 |
%g | %e ou %f, o que for mais curto, sem zeros à direita | 1234.5678 |
%v | o mesmo que %g | 1234.5678 |
%.2f arredonda o valor binário exato do float, então fmt.Sprintf("%.2f", 2.675) dá 2.67: o float64 mais próximo de 2.675 fica um pouco abaixo dele. Nunca formate dinheiro a partir de um float; guarde centavos em um inteiro.
Strings e bytes
| Verbo | Significado | fmt.Sprintf(verb, "go\n") |
|---|---|---|
%s | a string pura | go e uma quebra de linha |
%q | entre aspas duplas, com escapes visíveis | "go\n" |
%x | hexadecimal de cada byte | 676f0a |
% x | hexadecimal com espaços | 67 6f 0a |
%s em um []byte imprime como texto; %v imprime os números ([104 105]).
Outros tipos
| Verbo | Tipo | Imprime |
|---|---|---|
%t | bool | true ou false |
%p | ponteiro, slice, map, channel, func | o endereço, como 0xc000012345 |
%w | error (só no Errorf) | a mensagem do erro, e o empacota |
Largura, precisão e preenchimento
Entre o % e o verbo você pode colocar flags, uma largura e uma precisão:
| Forma | Efeito |
|---|---|
%5d | largura 5, alinhado à direita (preenche com espaços à esquerda) |
%-5d | largura 5, alinhado à esquerda |
%05d | preenche com zeros |
%.2f | 2 dígitos depois do ponto decimal |
%8.2f | largura 8 e 2 casas decimais |
%.3s | no máximo 3 caracteres da string |
%+d | sempre mostra o sinal |
%*d | largura tirada do próximo argumento |
Repare que %.0f de 2.5 imprime 2: aqui o Go arredonda a metade para o par. Em strings, a largura conta runes, não colunas na tela, então caracteres CJK e emoji ainda podem desalinhar uma tabela. Para colunas alinhadas de texto variável, o text/tabwriter faz a medição por você.
Índices de argumentos
%[n] escolhe um argumento pela posição, o que permite reutilizá-lo:
fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10) // 10 a 1010
Errorf e %w
fmt.Errorf monta um error a partir de uma string de formato. Com %w ele também empacota outro erro, então quem chama ainda consegue detectar o original:
Use %w quando quem chama pode precisar verificar a causa, e %v quando você quer escondê-la de propósito. Desde o Go 1.20 uma chamada de Errorf pode ter vários verbos %w. A página de tratamento de erros aprofunda o empacotamento.
Formatação personalizada com String()
Qualquer tipo com um método String() string controla como %v, %s e Println o exibem:
%d ignora o String() e imprime o número subjacente. Para tipos de erro, o método equivalente é Error() string, que tem prioridade sobre String().
Quando o verbo está errado
O fmt nunca causa panic por um formato ruim. Ele imprime o problema no meio da saída:
fmt.Printf("%d\n", "oops")
fmt.Printf("%d %d\n", 1)
fmt.Printf("%d\n", 1, 2)
%!d(string=oops)
1 %!d(MISSING)
1
%!(EXTRA int=2)
Essa saída costuma chegar à produção porque não derruba nada. O go vet pega os três na hora do build:
./main.go:8:2: fmt.Printf format %d has arg "oops" of wrong type string
./main.go:9:2: fmt.Printf format %d reads arg #2, but call has 1 arg
./main.go:10:2: fmt.Printf call needs 1 arg but has 2 args
Notas de desempenho
O fmt recebe todo argumento como any e inspeciona o tipo em tempo de execução (recorrendo a reflection para structs, slices e maps), o que não é problema para logs e saída, mas pesa em laços apertados. Para converter um único número, strconv.Itoa e strconv.FormatFloat são mais rápidos que Sprintf. Para montar uma string longa em um laço, escreva em um strings.Builder com fmt.Fprintf(&b, ...) em vez de concatenar resultados de Sprintf.
Perguntas frequentes
Qual a diferença entre Println, Printf e Sprintf em Go?
fmt.Println imprime os argumentos separados por espaço, com uma quebra de linha no final. fmt.Printf imprime de acordo com uma string de formato e não acrescenta quebra de linha. fmt.Sprintf formata do mesmo jeito que o Printf, mas devolve o resultado como string em vez de imprimir. fmt.Errorf faz o mesmo e devolve um error.
Como imprimir uma struct com os nomes dos campos em Go?
Use %+v: fmt.Printf("%+v\n", user) imprime {Name:Ana Age:31}. %v imprime só os valores, {Ana 31}, e %#v imprime sintaxe Go incluindo o tipo, main.User{Name:"Ana", Age:31}.
Como formatar um float com 2 casas decimais em Go?
Use %.2f: fmt.Sprintf("%.2f", 3.14159) devolve "3.14". Acrescente uma largura para alinhar colunas, %8.2f, ou um sinal de menos para alinhar à esquerda, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) dá o mesmo resultado sem string de formato.
O que %w faz no fmt.Errorf?
%w formata um erro como %v e também o empacota, então o novo erro carrega o original. errors.Is e errors.As conseguem então encontrar o erro empacotado: err := fmt.Errorf("load config: %w", os.ErrNotExist) faz errors.Is(err, os.ErrNotExist) ser true. %w só funciona no fmt.Errorf.
Por que minha saída mostra %!d(string=...)?
O verbo não bate com o tipo do argumento, por exemplo %d recebendo uma string. O fmt imprime o problema no meio da saída em vez de causar panic: %!d(string=oops). Argumentos faltando imprimem %!d(MISSING) e argumentos sobrando %!(EXTRA int=2). O go vet pega os três antes de você executar o programa.