Código da aula: Github

Introdução

Na aula anterior, exploramos conceitos avançados de ordenação em Go, utilizando funções de comparação personalizadas para ordenar dados complexos. Nesta aula, mudaremos o foco para um conceito fundamental no tratamento de erros em Go: o uso da função panic. O panic em Go é utilizado para indicar que algo inesperado ocorreu, levando o programa a terminar sua execução imediatamente. Essa abordagem é usada em situações onde não é possível ou desejável tratar o erro de forma convencional. Vamos explorar como e quando utilizar panic, com exemplos práticos aplicados no dia a dia de um desenvolvedor Go.

Exemplos Práticos

1. Abortando em Caso de Erro Irrecuperável

Uma das principais utilizações do panic é abortar a execução do programa em casos onde ocorra um erro que não é possível ou necessário tratar.
package main

import (
	"fmt"
	"os"
)

func main() {
	// Tenta criar o arquivo dentro do diretório ./temp que ainda não existe
	_, err := os.Create("./temp/file.txt")
	if err != nil {
		panic("Erro ao criar o arquivo ./temp/file.txt: " + err.Error())
	}

	fmt.Println("Arquivo criado com sucesso.")
}

Descrição:
  • panic("um problema inesperado aconteceu"): Dispara um panic com uma mensagem específica, encerrando o programa.
  • os.Create("/tmp/file"): Tenta criar um arquivo. Se houver algum erro, o panic(err) é disparado, exibindo o erro e terminando o programa.

2. Validando Pré-Condições com panic

Em alguns casos, você pode querer garantir que certas condições sejam verdadeiras antes de continuar a execução de uma função. Se essas condições não forem atendidas, um panic pode ser usado para interromper a execução.
package main

import "fmt"

func dividir(num, div float64) float64 {
    if div == 0 {
        panic("divisão por zero não permitida")
    }
    return num / div
}

func main() {
    fmt.Println("Resultado:", dividir(10, 2)) // Saída: Resultado: 5
    fmt.Println("Resultado:", dividir(10, 3)) // Saída: Resultado: 3.3333333333333335
    fmt.Println("Resultado:", dividir(10, 0)) // Isto irá disparar o panic
}

Descrição:

  • dividir: Uma função que realiza a divisão de dois números float64, mas dispara um panic se o divisor for zero.
  • panic("divisão por zero não permitida"): Dispara um panic com uma mensagem específica quando o divisor é zero, encerrando a execução da função e do programa.

3. Lidando com Recursos Críticos e Imprevistos

O panic também pode ser usado em situações onde um recurso crítico, como uma conexão com um banco de dados ou uma API, não pode ser obtido e é crucial para o funcionamento da aplicação. Antes de rodar o código, execute:
go mod init panic-example
Inicializa um novo módulo Go chamado panic-example, criando um arquivo go.mod que gerencia as dependências e configurações do projeto. Agora esse comando:
go mod tidy
O comando go mod tidy é usado para limpar e organizar as dependências no arquivo go.mod e no arquivo go.sum. Ele remove dependências que não são mais usadas no código e adiciona qualquer dependência que esteja faltando, garantindo que os arquivos de módulos reflitam exatamente as dependências necessárias para o projeto. Se ainda estiver tendo problema com o import do drive no mysql, tente executar esse comando:
go get -u github.com/go-sql-driver/mysql
Baixa e adiciona a última versão do pacote mysql como dependência do projeto, registrando-a no go.mod para uso no código. Agora pode executar o código.
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
)

func conectarBancoDeDados() *sql.DB {
    // Conexão com o MySQL
    connStr := "user:senha@/testdb?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := sql.Open("mysql", connStr)
    if err != nil {
        panic("falha ao conectar no banco de dados: " + err.Error())
    }

    // Verifica se a conexão está ativa
    err = db.Ping()
    if err != nil {
        panic("não foi possível estabelecer uma conexão ativa: " + err.Error())
    }

    return db
}

func main() {
    db := conectarBancoDeDados()
    defer db.Close()

    fmt.Println("Conexão com o banco de dados estabelecida com sucesso.")
}

Descrição:
  • conectarBancoDeDados: Função que tenta estabelecer uma conexão com o banco de dados. Se a conexão falhar, um panic é disparado com uma mensagem de erro.
  • panic("falha ao conectar no banco de dados: " + err.Error()): Dispara um panic com uma mensagem específica se ocorrer um erro ao tentar conectar ao banco de dados.
  • defer db.Close(): Garante que a conexão com o banco de dados será fechada ao final da execução da função main, mesmo que ocorra um panic.

Conclusão

Nesta aula, vimos como utilizar o panic para lidar com situações de erro que não podem ou não devem ser tratadas de maneira convencional. Aprendemos a usar panic para abortar a execução em casos de erro irrecuperável, validar pré-condições em funções e lidar com recursos críticos. O uso adequado do panic contribui para a robustez e segurança de suas aplicações em Go. Na próxima aula, exploraremos outro conceito fundamental em Go: o uso de defer, que permite adiar a execução de uma função até que a função que a contém termine.