Tratamento de erros em Go: try/catch e técnicas avançadas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Tratamento de erros em Go: try/catch e além: nível avançado



Desenvolvedores que vêm para Go de linguagens com exceções (Java, Python, C#) frequentemente perguntam: "Onde está o try/catch aqui?". A resposta é simples: Go não tem exceções no sentido clássico. Em vez disso, a linguagem oferece um modelo de tratamento de erros explícito, previsível e eficiente. À primeira vista, isso pode parecer um retrocesso, mas na prática é um dos princípios-chave da filosofia do Go — simplicidade e confiabilidade. Neste artigo, não vamos apenas mostrar como substituir o try/catch, mas explorar técnicas avançadas de trabalho com erros: desde tipos personalizados até encapsulamento e pânico.



Por que não há try/catch em Go?



A ausência de try/catch é uma decisão arquitetônica consciente. Exceções geralmente levam a fluxos de execução implícitos que são difíceis de rastrear. O programa pode "explodir" em qualquer lugar se você esquecer de tratar uma exceção. Go oferece uma abordagem diferente: o erro é apenas um valor (error is a value).



Isso significa que uma função que pode falhar retorna um valor de erro como parte de seu resultado. O programador deve verificar esse valor. Essa abordagem torna o fluxo de erros visível no código e evita situações em que a exceção é "engolida" ou tratada muito longe do local onde ocorreu.



// Expressão idiomática típica do Gofunc ReadFile(path string) ([]byte, error) {    data, err := os.ReadFile(path)    if err != nil {        return nil, fmt.Errorf("não foi possível ler o arquivo %s: %w", path, err)    }    return data, nil}

// Usodata, err := ReadFile("config.json")if err != nil { log.Fatal(err) // ou return err}


Esta é a substituição do try/catch. Em vez do bloco try { ... } catch (Exception e) { ... }, usamos if err != nil. Isso não é menos expressivo, mas é muito mais explícito.



Técnicas avançadas: erros personalizados e encapsulamento



1. Tipos de erro personalizados



O tipo padrão error é uma interface com um único método Error() string. Mas para tratamento avançado, você geralmente precisa de mais: código de erro, natureza temporária da falha, dados adicionais. Crie seu próprio tipo implementando a interface error.



type MyError struct {    Code    int    Message string    IsTemp  bool}

func (e *MyError) Error() string { return fmt.Sprintf("código %d: %s (temporário: %t)", e.Code, e.Message, e.IsTemp)}

// Usofunc DoSomething() error { return &MyError{Code: 503, Message: "serviço indisponível", IsTemp: true}}

// Verificaçãoerr := DoSomething()var myErr *MyErrorif errors.As(err, &myErr) { if myErr.IsTemp { // Tentar novamente }}


Dica: Use errors.As para conversão segura para seu tipo, em vez de conversão direta de tipo (type assertion), para evitar pânico.



2. Encapsulamento de erros (Wrapping)



Um dos recursos mais poderosos do Go 1.13+ é a capacidade de encapsular erros usando fmt.Errorf e a diretiva %w. Isso cria uma cadeia de erros que pode ser desfeita com errors.Is e errors.As.



func OpenConfig() error {    _, err := os.Open("config.yaml")    if err != nil {        // Encapsula o erro, adicionando contexto        return fmt.Errorf("abertura do config: %w", err)    }    return nil}

func LoadApp() error { err := OpenConfig() if err != nil { // Encapsula novamente return fmt.Errorf("carregamento da aplicação: %w", err) } return nil}

// Em algum lugar no mainerr := LoadApp()if errors.Is(err, os.ErrNotExist) { fmt.Println("Arquivo de configuração não encontrado")}


Observe: errors.Is percorre toda a cadeia e encontra

Blogs

Book Recommendations