O pacote fmt
A aula aborda o pacote fmt da linguagem Go, detalhando as funções de saída (Print, Printf, Sprintf), os verbos de formatação, a leitura de entrada (Scan) e boas práticas. O conteúdo inclui exemplos práticos e explicações aprofundadas para uso profissional.
O pacote fmt é um dos mais importantes da biblioteca padrão de Go, fornecendo funções para formatação e leitura de entrada e saída. Ele implementa formatação inspirada na linguagem C, mas com tipagem segura e extensibilidade. Dominar esse pacote é essencial para qualquer desenvolvedor Go, pois ele é usado tanto para depuração rápida quanto para produção de mensagens formatadas para o usuário.
Nesta aula, exploraremos as funções mais comuns de saída (Print, Printf, Sprintf), os verbos de formatação que controlam a aparência dos dados, as funções de entrada (Scan e variantes) e boas práticas para uso eficiente e correto.
Print, Printf, Sprintf
As funções Print, Printf e Sprintf são as principais para gerar saída formatada. Print simplesmente escreve os argumentos separados por espaços e adiciona uma nova linha ao final. Printf permite especificar um formato com verbos de formatação, sem adicionar nova linha automaticamente. Sprintf retorna a string formatada em vez de escrevê-la na saída padrão.
Exemplo prático:
package main
import "fmt"
func main() {
nome := "Maria"
idade := 30
altura := 1.75
// Print: espaços entre argumentos, nova linha no final
fmt.Print("Nome:", nome, "Idade:", idade)
// Printf: controle total com verbos
fmt.Printf("\nNome: %s, Idade: %d, Altura: %.2f\n", nome, idade, altura)
// Sprintf: retorna string formatada
mensagem := fmt.Sprintf("%s tem %d anos e %.2f m de altura.", nome, idade, altura)
fmt.Println(mensagem)
}A saída será:
Nome:Maria Idade:30
Nome: Maria, Idade: 30, Altura: 1.75
Maria tem 30 anos e 1.75 m de altura.Note que Print não insere espaços automaticamente entre a string e o valor, mas insere entre cada argumento. Já Printf requer que você especifique a formatação exata.
Verbos
Os verbos de formatação são códigos iniciados com % que controlam como os valores são convertidos para string. Os mais comuns são:
%v: valor padrão (default format)%+v: para structs, exibe nomes dos campos%#v: representação Go-syntax do valor%T: tipo do valor%d: inteiro decimal%b: binário%o: octal%x: hexadecimal (letras minúsculas)%X: hexadecimal (letras maiúsculas)%f: ponto flutuante decimal%e: notação científica (e minúsculo)%E: notação científica (E maiúsculo)%s: string%q: string entre aspas duplas, escapando caracteres especiais%p: ponteiro (endereço hexadecimal)
Exemplo:
package main
import "fmt"
func main() {
x := 255
fmt.Printf("Decimal: %d\n", x)
fmt.Printf("Binário: %b\n", x)
fmt.Printf("Octal: %o\n", x)
fmt.Printf("Hexadecimal: %x\n", x)
pi := 3.1415926535
fmt.Printf("Pi: %.2f\n", pi) // duas casas decimais
fmt.Printf("Pi: %e\n", pi)
str := "Olá, mundo!"
fmt.Printf("String: %s\n", str)
fmt.Printf("Quoted: %q\n", str)
}Saída:
Decimal: 255
Binário: 11111111
Octal: 377
Hexadecimal: ff
Pi: 3.14
Pi: 3.141593e+00
String: Olá, mundo!
Quoted: "Olá, mundo!"Além disso, é possível usar flags como + (sempre exibir sinal), - (alinhar à esquerda), 0 (preencher com zeros), e largura/precisão numérica.
Scan
O pacote fmt também oferece funções para leitura de entrada formatada: Scan, Scanf e Sscan (e suas variantes com ln). Scan lê valores separados por espaços da entrada padrão. Scanf lê de acordo com um formato especificado. Sscan lê de uma string.
Exemplo:
package main
import "fmt"
func main() {
var nome string
var idade int
fmt.Print("Digite seu nome e idade: ")
_, err := fmt.Scan(&nome, &idade)
if err != nil {
fmt.Println("Erro na leitura:", err)
return
}
fmt.Printf("Nome: %s, Idade: %d\n", nome, idade)
}Para leitura com formato específico:
package main
import "fmt"
func main() {
var nome string
var idade int
fmt.Print("Digite no formato 'Nome Idade': ")
_, err := fmt.Scanf("%s %d", &nome, &idade)
if err != nil {
fmt.Println("Erro:", err)
return
}
fmt.Printf("Lido: %s, %d\n", nome, idade)
}As funções Scanln e Scanf param na nova linha. Sscanf permite analisar uma string já existente.
Boas práticas
Ao usar o pacote fmt, algumas práticas ajudam a evitar erros e melhorar a legibilidade:
- Evite usar
Printpara debugging em produção: prefira o pacotelogou bibliotecas de logging estruturado. - Use
fmt.Errorfpara criar erros formatados: em vez defmt.Sprintf+errors.New, usefmt.Errorfque já retorna um erro. - Prefira
fmt.Fprint*para escrever emio.Writer: funções comofmt.Fprintfpermitem escrever em qualquer writer (arquivo, buffer, etc.), tornando o código mais flexível. - Cuidado com a ordem dos argumentos: em
Printf, a ordem dos verbos deve corresponder à ordem dos argumentos. Erros comuns são trocar a ordem ou esquecer argumentos. - Use
%vpara valores genéricos: quando não precisar de formatação específica,%vé suficiente e evita erros de tipo. - Verifique sempre os erros retornados por
Scan: a leitura pode falhar, e ignorar o erro pode levar a dados inconsistentes.
Exemplo de boas práticas:
package main
import (
"bytes"
"fmt"
)
func main() {
var buf bytes.Buffer
fmt.Fprintf(&buf, "Erro ao processar %s: %v", "arquivo.txt", fmt.Errorf("permissão negada"))
fmt.Println(buf.String())
}Isso demonstra o uso de Fprintf com um buffer, e fmt.Errorf para criar erros formatados.
Referências
- Documentação oficial do pacote fmt
- Strings, bytes, runes and characters in Go (Blog oficial)
- Go by Example: String Formatting
- YourBasic: fmt.Printf formatting cheat sheet
- Stack Overflow: How to print struct variables in console
- DigitalOcean: How To Use the fmt Package in Go
Exercícios
Escreva um programa que leia dois números inteiros do usuário usando
fmt.Scane imprima a soma comfmt.Printf, formatando o resultado como "Soma: X".✓ Resposta:package main import "fmt" func main() { var a, b int fmt.Print("Digite dois números: ") _, err := fmt.Scan(&a, &b) if err != nil { fmt.Println("Erro:", err) return } fmt.Printf("Soma: %d\n", a+b) }Crie uma struct
Pessoacom camposNomeeIdade. Usefmt.Printfcom o verbo%+vpara imprimir uma instância.✓ Resposta:package main import "fmt" type Pessoa struct { Nome string Idade int } func main() { p := Pessoa{"João", 25} fmt.Printf("%+v\n", p) }Use
fmt.Sprintfpara criar uma mensagem formatada a partir de variáveis e depois imprima-a comfmt.Println.✓ Resposta:package main import "fmt" func main() { nome := "Ana" idade := 28 msg := fmt.Sprintf("%s tem %d anos.", nome, idade) fmt.Println(msg) }Leia uma linha inteira do usuário usando
fmt.Scanlne imprima o que foi lido comfmt.Printfusando o verbo%q.✓ Resposta:package main import "fmt" func main() { var linha string fmt.Print("Digite algo: ") _, err := fmt.Scanln(&linha) if err != nil { fmt.Println("Erro:", err) return } fmt.Printf("Você digitou: %q\n", linha) }Escreva um programa que use
fmt.Errorfpara criar um erro formatado com a mensagem "Erro ao abrir arquivo:" e imprima o erro. ✓ Resposta:package main import "fmt" func main() { nome := "dados.txt" err := fmt.Errorf("Erro ao abrir arquivo: %s", nome) fmt.Println(err) }