Golang ou Go possui um mecanismo robusto de tratamento de erros que é parte integrante do design da linguagem. Embora Go forneça tipos de erro integrados, há situações em que você pode precisar de mais controle e contexto no tratamento de erros.
É aqui que entra em jogo a criação de erros personalizados. Erros personalizados podem fornecer mensagens de erro mais informativas e podem ser usados para categorizar diferentes tipos de erros em seu aplicativo.
Neste artigo, exploraremos como criar e usar erros personalizados em Golang de maneira eficaz.
No Go, o tipo de erro é uma interface integrada semelhante a esta:
type error interface { Error() string }
Qualquer tipo que implemente o método Error() com um tipo de retorno string satisfaz esta interface e pode ser considerado um erro. Isso é simples, mas poderoso porque permite criar tipos de erro personalizados simplesmente implementando esse método.
Aqui está um exemplo rápido de tratamento básico de erros em Go:
package main import ( "errors" "fmt" ) func main() { err := doSomething() if err != nil { fmt.Println("Error:", err) } } func doSomething() error { return errors.New("something went wrong") }
Este exemplo usa a função erros.New para criar um erro básico. Embora seja útil para casos simples, falta-lhe a capacidade de fornecer mais contexto ou de distinguir entre diferentes tipos de erros.
Erros personalizados são essenciais quando você precisa de mensagens de erro mais descritivas ou quando deseja lidar com diferentes tipos de erros de maneira diferente. Por exemplo, talvez você queira retornar um tipo de erro específico quando um arquivo não for encontrado e outro tipo quando um arquivo estiver corrompido. Erros personalizados também podem conter dados adicionais, facilitando a depuração e fornecendo informações mais detalhadas ao chamador.
Para criar um erro personalizado em Go, você define um novo tipo que implementa o método Error(). Vejamos um exemplo.
Veja como você pode criar um erro personalizado simples:
package main import ( "fmt" ) type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("Code %d: %s", e.Code, e.Message) } func main() { err := doSomething() if err != nil { fmt.Println("Error:", err) } } func doSomething() error { return &MyError{ Code: 404, Message: "Resource not found", } }
Neste exemplo, MyError é um tipo de erro personalizado que inclui um código e uma mensagem. O método Error() os formata em uma string, facilitando a impressão ou registro do erro.
Às vezes, é útil comparar os erros diretamente. É aqui que entram os erros sentinela. Um erro sentinela é uma variável predefinida e exportada que representa um erro específico.
package main import ( "errors" "fmt" ) var ErrNotFound = errors.New("resource not found") func main() { err := doSomething() if errors.Is(err, ErrNotFound) { fmt.Println("Error:", err) } } func doSomething() error { return ErrNotFound }
Embora essa abordagem seja direta, combinar valores sentinela com tipos de erro personalizados pode ser ainda mais poderoso, permitindo comparação de erros e dados de erro ricos.
Go 1.13 introduziu a função fmt.Errorf com verbo %w, que permite agrupar erros, adicionando mais contexto enquanto preserva o erro original.
package main import ( "errors" "fmt" ) var ErrNotFound = errors.New("resource not found") func main() { err := doSomething() if err != nil { fmt.Println("Error:", err) if errors.Is(err, ErrNotFound) { fmt.Println("The resource was not found.") } } } func doSomething() error { err := fetchResource() if err != nil { return fmt.Errorf("failed to do something: %w", err) } return nil } func fetchResource() error { return ErrNotFound }
Isso permite que você verifique erros específicos e também mantenha uma pilha de erros que fornece mais contexto sobre o que deu errado.
Go também fornece uma maneira de extrair o erro empacotado usando o método Unwrap(). Ao implementar esse método em seus tipos de erro personalizados, você pode permitir a desempacotamento adicional de erros.
package main import ( "errors" "fmt" ) type MyError struct { Code int Message string Err error } func (e *MyError) Error() string { return fmt.Sprintf("Code %d: %s", e.Code, e.Message) } func (e *MyError) Unwrap() error { return e.Err } func main() { err := doSomething() if err != nil { fmt.Println("Error:", err) if errors.Is(err, ErrNotFound) { fmt.Println("The resource was not found.") } } } var ErrNotFound = errors.New("resource not found") func doSomething() error { err := fetchResource() if err != nil { return &MyError{ Code: 500, Message: "Something went wrong", Err: err, } } return nil } func fetchResource() error { return ErrNotFound }
Aqui, MyError tem um método Unwrap() que retorna o erro empacotado. Isso permite uma inspeção e tratamento mais profundos do erro subjacente.
Go também fornece uma maneira de extrair o erro com o método errors.As. Ao implementar esse método em seus tipos de erro personalizados, você pode verificar o tipo de erro e também buscar os valores de erro personalizados.
package main import ( "errors" "fmt" ) type MyError struct { Code int Message string Err error } func (e *MyError) Error() string { return fmt.Sprintf("Code %d: %s: %v", e.Code, e.Message, e.Err) } func main() { err := doSomething() var mErr *MyError // another way to initialize custom error // mErr := &MyError{} if errors.As(err, &mErr) { fmt.Println("Error:", mErr) } } // doSomething attempts to fetch a resource and returns an error if it fails. // If the error is ErrNotFound, it is wrapped in a MyError with a code of 500. func doSomething() error { err := fetchResource() if err != nil { return &MyError{ Code: 500, Message: "Something went wrong", Err: err, } } return nil } var ErrNotFound = errors.New("resource not found") func fetchResource() error { return ErrNotFound }
Use erros personalizados com moderação: Erros personalizados são poderosos, mas podem adicionar complexidade. Use-os quando eles oferecem benefícios significativos, como melhor categorização de erros ou contexto adicional.
Aproveite o empacotamento e o desempacotamento: Encapsular erros com contexto adicional e desempacotá-los posteriormente é uma prática recomendada que aprimora a depuração de erros.
Documente seus tipos de erro: Certifique-se de que quaisquer erros personalizados estejam bem documentados para que sua finalidade e uso sejam claros.
Prefira valores de erro para comparação: Quando você precisar comparar erros, considere usar valores de erro predefinidos (erros sentinela) para consistência e clareza.
Erros personalizados em Go fornecem uma maneira flexível e poderosa de gerenciar erros em seus aplicativos. Ao criar seus próprios tipos de erro, agrupar os erros para obter contexto adicional e desembrulhá-los para uma inspeção mais profunda, você pode criar mecanismos de tratamento de erros robustos e sustentáveis. Isso não apenas ajuda na depuração, mas também melhora a qualidade geral do seu código Go.
Escolha sua estratégia com os erros e use os erros consistentes em todo o projeto.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3