Carregando
Todos os artigos
Programação 5 min de leitura

Como Tratar Erros em Go: Um Guia Prático

Aprenda a tratar erros em Go com exemplos executáveis: retorne um erro, confira o resultado, acrescente contexto com %w e reconheça um arquivo ausente com errors.Is.

nbkhope
Nesta página

Como Tratar Erros em Go: Um Guia Prático

Programas encontram problemas: um arquivo não existe, um número é inválido ou uma requisição de rede falha. Em Go, uma função normalmente retorna um valor de erro para que a função que a chamou decida o que fazer. Você verá esse padrão em uma conta pequena e depois em um programa que lê um arquivo de verdade.

Este guia continua Seu Primeiro Programa em Go. Se você já usou defer para fazer a limpeza, guarde a ideia: tratar o erro define o que fazer quando uma operação falha; defer ajuda a liberar recursos depois de uma preparação bem-sucedida.

Uma função Go retorna um resultado e um erro; quem a chamou verifica o erro e escolhe uma ação.

Retorne um valor e um erro

Uma função Go pode retornar mais de um valor. Uma assinatura comum é (resultado, error): devolva o resultado com nil em caso de sucesso, ou um valor zero com um erro diferente de nil em caso de falha.

Salve o exemplo como main.go e rode go run main.go:

1package main
2
3import (
4    "errors"
5    "fmt"
6)
7
8func dividir(a, b int) (int, error) {
9    if b == 0 {
10        return 0, errors.New("não é possível dividir por zero")
11    }
12    return a / b, nil
13}
14
15func main() {
16    for _, divisor := range []int{2, 0} {
17        resultado, err := dividir(12, divisor)
18        if err != nil {
19            fmt.Println("a divisão falhou:", err)
20            continue
21        }
22        fmt.Println("resultado:", resultado)
23    }
24}
resultado: 6
a divisão falhou: não é possível dividir por zero

O teste if err != nil aparece antes de usar resultado. Quem chamou a função pode tentar outra entrada, mostrar uma mensagem ou devolver o erro para seu próprio chamador. Um erro é um valor; não é uma ordem para encerrar o programa.

Leia um arquivo e acrescente contexto

Agora substitua o conteúdo de main.go pelo programa abaixo. Ele lê um arquivo de texto local chamado mensagem.txt. Há dois resultados úteis: mostrar o conteúdo ou avisar que o arquivo não existe.

1package main
2
3import (
4    "errors"
5    "fmt"
6    "os"
7    "strings"
8)
9
10func carregarMensagem(caminho string) (string, error) {
11    dados, err := os.ReadFile(caminho)
12    if err != nil {
13        return "", fmt.Errorf("carregar mensagem %q: %w", caminho, err)
14    }
15    return strings.TrimSpace(string(dados)), nil
16}
17
18func main() {
19    mensagem, err := carregarMensagem("mensagem.txt")
20    if err != nil {
21        if errors.Is(err, os.ErrNotExist) {
22            fmt.Println("mensagem.txt não existe; crie o arquivo e tente novamente")
23            return
24        }
25        fmt.Println("não foi possível carregar a mensagem:", err)
26        return
27    }
28    fmt.Println("mensagem:", mensagem)
29}

Rode em uma pasta sem mensagem.txt:

mensagem.txt não existe; crie o arquivo e tente novamente

Depois crie mensagem.txt com o texto Olá, Go! e rode outra vez:

mensagem: Olá, Go!

O programa usa os.ReadFile, que lê e fecha o arquivo para você. Se você abrir um arquivo com os.Open, precisará fechá-lo; aí defer arquivo.Close() costuma ser útil.

Por que %w e errors.Is funcionam juntos?

Esta linha acrescenta a operação e o nome do arquivo ao erro:

return "", fmt.Errorf("carregar mensagem %q: %w", caminho, err)

O verbo %w encapsula o erro original. As palavras extras ajudam a entender onde a falha aconteceu, mas o erro original continua disponível para inspeção. errors.Is(err, os.ErrNotExist) percorre essa cadeia e reconhece o arquivo ausente mesmo depois que carregarMensagem acrescenta contexto. A mensagem exata produzida por os.ReadFile pode variar entre sistemas operacionais; verificar a identidade do erro é mais confiável do que procurar palavras no texto.

Com %v no lugar de %w, a mensagem ainda aparece, mas o erro original não fica encapsulado para errors.Is encontrá-lo. Comparar diretamente o erro encapsulado com err == os.ErrNotExist também pode deixar passar a correspondência. Encapsule um erro quando quem chama a função precisa reconhecê-lo ou inspecioná-lo; em uma função pública, essa escolha pode fazer parte da API.

Uma tabela para decidir

SituaçãoResposta comum
A função conclui o trabalhoRetorne o resultado e nil
A função não consegue concluirRetorne um valor zero e um erro com contexto útil
Quem chamou consegue se recuperarConfira o erro e siga um caminho alternativo
Quem chamou não consegue se recuperarDevolva o erro ou mostre-o no limite do programa

Não ignore um erro só para encurtar o código. panic não é a resposta normal para uma situação esperada, como a ausência de um arquivo fornecido pelo usuário.

Experimente

Modifique carregarMensagem para devolver um erro quando o arquivo estiver vazio ou contiver apenas espaços. Preserve o tratamento do arquivo ausente. Uma resposta possível é:

1func carregarMensagem(caminho string) (string, error) {
2    dados, err := os.ReadFile(caminho)
3    if err != nil {
4        return "", fmt.Errorf("carregar mensagem %q: %w", caminho, err)
5    }
6    mensagem := strings.TrimSpace(string(dados))
7    if mensagem == "" {
8        return "", fmt.Errorf("carregar mensagem %q: o arquivo está vazio", caminho)
9    }
10    return mensagem, nil
11}

Faça três testes: sem arquivo, com arquivo vazio e com texto. O caso do arquivo ausente ainda deve corresponder a os.ErrNotExist; o arquivo vazio deve chegar à mensagem geral de erro.

Cola rápida

1valor, err := fazerTrabalho()
2if err != nil {
3    if errors.Is(err, os.ErrNotExist) {
4        // Trate especificamente um arquivo ausente.
5    }
6    return fmt.Errorf("fazer trabalho: %w", err)
7}
8usar(valor)

Confira os erros quando surgem, acrescente contexto enquanto eles sobem pelas funções e escolha a mensagem para a pessoa no limite do programa. Esse ritmo simples resolve muitas falhas do dia a dia sem esconder o que aconteceu.

Para saber mais

Obrigado pela leitura!

Conhece alguém que vai gostar? Mande para essa pessoa.

Mais artigos

Leia a seguir

Comentários

Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.