Golang

A biblioteca padrão: um tour pelas principais ferramentas Já leu

10 min de leitura

A biblioteca padrão: um tour pelas principais ferramentas
Uma das razões pelas quais Go se tornou a linguagem preferida para infraestrutura e backends é a qualidade excepcional de sua biblioteca padr&atil

Uma das razões pelas quais Go se tornou a linguagem preferida para infraestrutura e backends é a qualidade excepcional de sua biblioteca padrão. Ela cobre HTTP, JSON, criptografia, compressão, templates, testes, banco de dados, manipulação de strings, tempo, sistema de arquivos e muito mais — tudo isso sem dependências externas, com APIs consistentes e documentação exemplar.

Em muitos casos, o que em outras linguagens exigiria três ou quatro bibliotecas externas é resolvido puramente com a biblioteca padrão do Go. Conhecê-la bem reduz dependências, simplifica projetos e evita a fragmentação de ecossistema que afeta outras comunidades.

Este artigo faz um tour pelos pacotes mais importantes, com exemplos práticos de cada um.


fmt — Formatação e I/O

Já presente em todos os artigos anteriores, fmt merece um olhar mais atento. Além de Println e Printf, oferece funções para escrever em qualquer io.Writer e para escanear entrada:

package main

import (
    "fmt"
    "os"
    "strings"
)

func main() {
    // Escrevendo em qualquer Writer
    fmt.Fprintln(os.Stderr, "erro: arquivo não encontrado")
    fmt.Fprintf(os.Stdout, "processados: %d itens\n", 42)

    // Formatando para string
    s := fmt.Sprintf("coordenadas: (%.4f, %.4f)", -23.5505, -46.6333)
    fmt.Println(s)

    // Lendo de qualquer Reader
    r := strings.NewReader("42 true Go")
    var n int
    var b bool
    var lang string
    fmt.Fscan(r, &n, &b, &lang)
    fmt.Println(n, b, lang) // 42 true Go

    // Verificação de erros com Errorf
    err := fmt.Errorf("operação falhou: código %d", 500)
    fmt.Println(err)
}

strings — Manipulação de strings

O pacote strings oferece tudo que se precisa para trabalhar com texto:

package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "  Olá, Mundo em Go!  "

    fmt.Println(strings.TrimSpace(s))              // "Olá, Mundo em Go!"
    fmt.Println(strings.ToUpper(s))                // "  OLÁ, MUNDO EM GO!  "
    fmt.Println(strings.ToLower(s))                // "  olá, mundo em go!  "
    fmt.Println(strings.Contains(s, "Mundo"))      // true
    fmt.Println(strings.HasPrefix(s, "  Olá"))    // true
    fmt.Println(strings.HasSuffix(s, "Go!  "))    // true
    fmt.Println(strings.Count(s, "o"))             // 2
    fmt.Println(strings.Replace(s, "Mundo", "Go", 1))
    fmt.Println(strings.Index(s, "Mundo"))         // 7

    // Split e Join
    partes := strings.Split("a,b,c,d", ",")
    fmt.Println(partes)                            // [a b c d]
    fmt.Println(strings.Join(partes, " | "))       // a | b | c | d

    // Fields divide por qualquer espaço em branco
    palavras := strings.Fields("  Go   é   rápido  ")
    fmt.Println(palavras)                          // [Go é rápido]

    // Builder para concatenação eficiente
    var sb strings.Builder
    for i := 0; i < 5; i++ {
        fmt.Fprintf(&sb, "item%d ", i)
    }
    fmt.Println(sb.String())
}

strconv — Conversões entre string e tipos

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // int ↔ string
    fmt.Println(strconv.Itoa(42))           // "42"
    n, _ := strconv.Atoi("123")
    fmt.Println(n + 1)                      // 124

    // float ↔ string
    f, _ := strconv.ParseFloat("3.14", 64)
    fmt.Println(f * 2)                      // 6.28
    fmt.Println(strconv.FormatFloat(f, 'f', 3, 64)) // "3.140"

    // bool ↔ string
    b, _ := strconv.ParseBool("true")
    fmt.Println(b)                          // true
    fmt.Println(strconv.FormatBool(false))  // "false"

    // int com base
    fmt.Println(strconv.FormatInt(255, 16)) // "ff"
    fmt.Println(strconv.FormatInt(255, 2))  // "11111111"
    v, _ := strconv.ParseInt("ff", 16, 64)
    fmt.Println(v)                          // 255
}

time — Data, hora e duração

package main

import (
    "fmt"
    "time"
)

func main() {
    agora := time.Now()
    fmt.Println(agora)

    // Formatação — Go usa uma data de referência específica: Mon Jan 2 15:04:05 MST 2006
    fmt.Println(agora.Format("02/01/2006 15:04:05"))
    fmt.Println(agora.Format(time.RFC3339))

    // Parsing
    t, _ := time.Parse("02/01/2006", "15/03/2024")
    fmt.Println(t.Year(), t.Month(), t.Day())

    // Aritmética com tempo
    amanha := agora.Add(24 * time.Hour)
    semanaPassada := agora.AddDate(0, 0, -7)
    fmt.Println(amanha.Format("02/01/2006"))
    fmt.Println(semanaPassada.Format("02/01/2006"))

    // Diferença entre datas
    diferenca := amanha.Sub(agora)
    fmt.Println(diferenca)               // 24h0m0s
    fmt.Println(diferenca.Hours())       // 24

    // Comparação
    fmt.Println(agora.Before(amanha))    // true
    fmt.Println(agora.After(amanha))     // false

    // Timer e Ticker
    timer := time.NewTimer(100 * time.Millisecond)
    <-timer.C
    fmt.Println("timer disparou")

    // Sleep
    time.Sleep(10 * time.Millisecond)
    fmt.Println("após sleep")
}

A data de referência Mon Jan 2 15:04:05 MST 2006 é um mnemônico: 1-2-3-4-5-6-7 (mês-dia-hora-minuto-segundo-ano-fuso). É única no Go e confunde iniciantes — mas uma vez memorizada, a formatação de datas torna-se intuitiva.


os — Sistema operacional e arquivos

package main

import (
    "fmt"
    "os"
)

func main() {
    // Variáveis de ambiente
    home := os.Getenv("HOME")
    fmt.Println("HOME:", home)
    os.Setenv("APP_ENV", "producao")

    // Argumentos da linha de comando
    fmt.Println("Argumentos:", os.Args)

    // Escrevendo arquivo
    err := os.WriteFile("saida.txt", []byte("conteúdo do arquivo\n"), 0644)
    if err != nil {
        fmt.Println("Erro ao escrever:", err)
        return
    }

    // Lendo arquivo
    dados, err := os.ReadFile("saida.txt")
    if err != nil {
        fmt.Println("Erro ao ler:", err)
        return
    }
    fmt.Print(string(dados))

    // Informações sobre arquivo
    info, err := os.Stat("saida.txt")
    if err == nil {
        fmt.Println("Tamanho:", info.Size(), "bytes")
        fmt.Println("Modificado:", info.ModTime().Format("02/01/2006"))
    }

    // Criando diretórios
    os.MkdirAll("dados/temp", 0755)

    // Removendo
    os.Remove("saida.txt")
    os.RemoveAll("dados")

    // Saindo com código de status
    // os.Exit(1) — encerra o programa imediatamente
}

io e bufio — I/O eficiente

package main

import (
    "bufio"
    "fmt"
    "io"
    "strings"
)

func main() {
    // io.Reader → io.Writer com Copy
    origem := strings.NewReader("dados a copiar\n")
    destino := &strings.Builder{}
    n, _ := io.Copy(destino, origem)
    fmt.Printf("copiados %d bytes: %s", n, destino.String())

    // bufio.Scanner para leitura linha por linha
    texto := "linha 1\nlinha 2\nlinha 3\n"
    scanner := bufio.NewScanner(strings.NewReader(texto))
    for scanner.Scan() {
        fmt.Println("→", scanner.Text())
    }

    // bufio.Writer para escrita com buffer
    bw := bufio.NewWriter(io.Discard) // io.Discard descarta tudo
    fmt.Fprintln(bw, "linha com buffer")
    bw.Flush() // importante: descarregar o buffer

    // io.LimitReader — limita quantidade de bytes lidos
    r := io.LimitReader(strings.NewReader("texto longo demais"), 5)
    dados, _ := io.ReadAll(r)
    fmt.Println(string(dados)) // "texto"

    // io.MultiWriter — escreve em múltiplos destinos simultaneamente
    var b1, b2 strings.Builder
    mw := io.MultiWriter(&b1, &b2)
    fmt.Fprintln(mw, "enviado para dois lugares")
    fmt.Println(b1.String() == b2.String()) // true
}

encoding/json — Serialização JSON

package main

import (
    "encoding/json"
    "fmt"
)

type Endereco struct {
    Rua    string `json:"rua"`
    Cidade string `json:"cidade"`
    CEP    string `json:"cep"`
}

type Usuario struct {
    ID       int      `json:"id"`
    Nome     string   `json:"nome"`
    Email    string   `json:"email"`
    Endereco Endereco `json:"endereco"`
    Ativo    bool     `json:"ativo"`
    Senha    string   `json:"-"`
}

func main() {
    // Struct → JSON (Marshal)
    u := Usuario{
        ID:    1,
        Nome:  "Ricardo",
        Email: "ricardo@exemplo.com",
        Endereco: Endereco{
            Rua:    "Av. Paulista, 1000",
            Cidade: "São Paulo",
            CEP:    "01310-100",
        },
        Ativo: true,
        Senha: "secreta",
    }

    dados, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        fmt.Println("Erro:", err)
        return
    }
    fmt.Println(string(dados))

    // JSON → Struct (Unmarshal)
    jsonStr := `{"id":2,"nome":"Ana","email":"ana@exemplo.com","ativo":false}`
    var u2 Usuario
    if err := json.Unmarshal([]byte(jsonStr), &u2); err != nil {
        fmt.Println("Erro:", err)
        return
    }
    fmt.Printf("%+v\n", u2)

    // Decodificação incremental com Decoder
    // útil para streams e arquivos grandes
    decoder := json.NewDecoder(strings.NewReader(jsonStr))
    var u3 map[string]any
    decoder.Decode(&u3)
    fmt.Println(u3["nome"]) // Ana
}

net/http — Cliente e servidor HTTP

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

// Servidor HTTP simples
func servidorExemplo() {
    mux := http.NewServeMux()

    mux.HandleFunc("GET /saude", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
    })

    mux.HandleFunc("GET /usuarios/{id}", func(w http.ResponseWriter, r *http.Request) {
        id := r.PathValue("id")
        fmt.Fprintf(w, "usuário: %s", id)
    })

    servidor := &http.Server{
        Addr:         ":8080",
        Handler:      mux,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    fmt.Println("Servidor em :8080")
    servidor.ListenAndServe()
}

// Cliente HTTP com timeout e tratamento de erros
func clienteExemplo() {
    cliente := &http.Client{Timeout: 10 * time.Second}

    resp, err := cliente.Get("https://httpbin.org/json")
    if err != nil {
        fmt.Println("Erro:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Status:", resp.Status)
    corpo, _ := io.ReadAll(resp.Body)
    fmt.Println(string(corpo[:100]))
}

O roteamento com padrões como GET /usuarios/{id} foi introduzido no Go 1.22, tornando o roteamento básico possível sem bibliotecas externas.


math e math/rand — Operações matemáticas

package main

import (
    "fmt"
    "math"
    "math/rand/v2"
)

func main() {
    // math
    fmt.Println(math.Sqrt(144))          // 12
    fmt.Println(math.Pow(2, 10))         // 1024
    fmt.Println(math.Abs(-42.5))         // 42.5
    fmt.Println(math.Round(3.7))         // 4
    fmt.Println(math.Floor(3.9))         // 3
    fmt.Println(math.Ceil(3.1))          // 4
    fmt.Println(math.Log(math.E))        // 1
    fmt.Println(math.Log2(1024))         // 10
    fmt.Println(math.MaxInt64)           // 9223372036854775807
    fmt.Println(math.Pi)                 // 3.141592653589793

    // math/rand/v2 — Go 1.22+
    fmt.Println(rand.IntN(100))          // inteiro aleatório [0, 100)
    fmt.Println(rand.Float64())          // float [0.0, 1.0)
    fmt.Println(rand.N(50))              // genérico — inteiro [0, 50)
}

sort — Ordenação

package main

import (
    "fmt"
    "sort"
)

type Produto struct {
    Nome  string
    Preco float64
}

func main() {
    // Tipos básicos
    nums := []int{5, 2, 8, 1, 9, 3}
    sort.Ints(nums)
    fmt.Println(nums) // [1 2 3 5 8 9]

    palavras := []string{"banana", "maçã", "abacaxi", "uva"}
    sort.Strings(palavras)
    fmt.Println(palavras) // [abacaxi banana maçã uva]

    // Verificando se está ordenado
    fmt.Println(sort.IntsAreSorted(nums)) // true

    // Tipos personalizados com sort.Slice
    produtos := []Produto{
        {"Monitor", 1500.0},
        {"Teclado", 250.0},
        {"Mouse", 120.0},
        {"Headset", 380.0},
    }

    // Ordenar por preço crescente
    sort.Slice(produtos, func(i, j int) bool {
        return produtos[i].Preco < produtos[j].Preco
    })

    for _, p := range produtos {
        fmt.Printf("%-10s R$ %.2f\n", p.Nome, p.Preco)
    }

    // Busca binária em slice ordenado
    idx := sort.SearchInts(nums, 5)
    fmt.Println("índice do 5:", idx) // 3
}

log e log/slog — Logging

package main

import (
    "log"
    "log/slog"
    "os"
)

func main() {
    // log padrão
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
    log.Println("aplicação iniciada")
    log.Printf("porta: %d", 8080)
    // log.Fatal chama os.Exit(1) após logar
    // log.Panic chama panic() após logar

    // slog — logging estruturado (Go 1.21+)
    logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug,
    }))

    logger.Info("servidor iniciado",
        "porta", 8080,
        "ambiente", "producao",
    )

    logger.Warn("memória alta",
        "uso_mb", 512,
        "limite_mb", 1024,
    )

    logger.Error("falha na conexão",
        "host", "localhost",
        "erro", "connection refused",
    )
}

path/filepath — Caminhos de arquivo

package main

import (
    "fmt"
    "path/filepath"
)

func main() {
    // Construindo caminhos portáveis
    p := filepath.Join("dados", "usuarios", "perfil.json")
    fmt.Println(p) // dados/usuarios/perfil.json (Linux/Mac)

    fmt.Println(filepath.Dir(p))        // dados/usuarios
    fmt.Println(filepath.Base(p))       // perfil.json
    fmt.Println(filepath.Ext(p))        // .json

    // Caminho absoluto
    abs, _ := filepath.Abs("main.go")
    fmt.Println(abs)

    // Percorrendo diretórios
    filepath.Walk(".", func(caminho string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if !info.IsDir() {
            fmt.Println(caminho)
        }
        return nil
    })
}

Resumo do que foi coberto

Este artigo percorreu os pacotes mais importantes da biblioteca padrão do Go: fmt, strings, strconv, time, os, io, bufio, encoding/json, net/http, math, sort, log/slog e path/filepath. Cada pacote foi apresentado com exemplos práticos que cobrem os casos de uso mais comuns. A biblioteca padrão é vasta — este artigo é um ponto de partida, não um limite.


Referências e leituras complementares

  • pkg.go.dev — Biblioteca padrão completa — Documentação oficial de todos os pacotes. https://pkg.go.dev/std

  • Go by Example — Exemplos práticos para cada pacote da biblioteca padrão. https://gobyexample.com

  • Documentação net/http — Referência completa do servidor e cliente HTTP. https://pkg.go.dev/net/http

  • Go Blog: Structured Logging with slog — Introdução ao novo pacote de logging estruturado. https://go.dev/blog/slog

  • Go Blog: Working with JSON — Guia completo de encoding/json. https://go.dev/blog/json

  • Documentação time — Format e Parse — Referência dos layouts de formatação de datas. https://pkg.go.dev/time#Time.Format

Comentários

Mais em Golang

Maps: criação, iteração e boas práticas
Maps: criação, iteração e boas práticas

Se slices s&atilde;o a espinha dorsal das sequ&ecirc;ncias em Go, maps s&atil...

Funções: declaração, múltiplos retornos e variádicas
Funções: declaração, múltiplos retornos e variádicas

Em Go, fun&ccedil;&otilde;es s&atilde;o cidad&atilde;s de primeira classe. El...

Operadores, expressões e conversão de tipo
Operadores, expressões e conversão de tipo

Se vari&aacute;veis s&atilde;o os substantivos de um programa, operadores s&a...