Pular para o conteúdo principal

victorstein.dev

35/100 Dias de Golang - Error Handling

Table of Contents

# Error Handling

O tratamento de erros em Go é bem diferente do que em outras linguagem, não temos o tradicional try/except. Os erros em Go são simplesmente retornados como uma variável normal, daí que surge o famoso if err != nil {} do Golang. Nas primeiras vezes que vi essa estrutura foi meio estranho, mas depois fez bastante sentido. Essa estrutura vai completamente de encontro ao design da linguagem do Golang, manter a simplicidade e eficiencia da linguagem. Vamos criar uma função de divisão e retornar um erro quando o divisor é 0.

func Divisao(a, b int) (int, error) {
	if b == 0 {
		return 0, fmt.Errorf("Não posso dividr '%d' por zero", a)
	}
	return a / b, nil
}

func main() {

	resultado, err := Divisao(1, 0)

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(resultado)
	}
}

Podemos criar um erro personalizado:

var ErroDividePorZero = errors.New("Não posso dividr por zero")

func Divisao(a, b int) (int, error) {
	if b == 0 {
		return 0, ErroDividePorZero
	}
	return a / b, nil
}

func main() {

	resultado, err := Divisao(1, 0)

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(resultado)
	}
}

# Panic e Recover

A linguagem também oferece as funções panic e recover para situações realmente excepcionais, como bugs inesperados ou falhas graves. A função panic interrompe a execução normal do programa e o recover pode ser usado dentro de uma função defer para capturar um panic e evitar que o programa termine abruptamente.

func podeEntrarEmPanico() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recuperado do pânico:", r)
		}
	}()
	panic("Algo muito errado aconteceu!")
}
func main() {
	podeEntrarEmPanico()
}

# Exemplo de Propagação e Tratamento de Erros

A função responsável por tratar o erro é aquela que tem contexto suficiente para tomar uma decisão adequada. Por exemplo, se uma função de leitura de arquivo falha, ela deve apenas retornar o erro. Já a função que chamou essa leitura pode decidir se tenta novamente, mostra uma mensagem para o usuário, ou encerra o programa.

func lerArquivo(nome string) ([]byte, error) {
    dados, err := os.ReadFile(nome)
    if err != nil {
        return nil, err 
    }
    return dados, nil
}

func processarArquivo(nome string) error {
    dados, err := lerArquivo(nome)
    if err != nil {
        return fmt.Errorf("falha ao processar arquivo %s: %w", nome, err)
    }
    // Processa os dados...
    return nil
}

func main() {
    err := processarArquivo("dados.txt")
    if err != nil {
        log.Fatalf("Erro fatal: %w", err) // Tratamento final do erro
    }
}

Veja a saída:

2025/04/16 14:18:10 Erro fatal: falha ao processar arquivo dados.txt: open dados.txt: no such file or directory

Veja que vamos propagando o erro e adicionando contexto a mensagem, na função processarArquivo, retornamos return fmt.Errorf("falha ao processar arquivo %s: %w", nome, err). Tratamento de erros é um assunto bem complexo que podemos falar mais em outros posts, essa foi só uma introdução. Segue algumas referências:

# Referências