How to create structured error types in Go for better error handling?

In Go, error handling is usually done using the built-in error type, which is an interface that represents an error with a single error message. However, sometimes you may need more structured error types to provide additional information or context.

Here are the steps to create structured error types in Go for better error handling:

  1. Define a custom error struct: Create a new struct that represents your error type. You can include fields to store additional information related to the error.
type MyError struct { message string code int }
  1. Implement the error interface: To make your custom error type compatible with the built-in error handling mechanism, you need to implement the Error() method of the error interface.
func (e MyError) Error() string { return fmt.Sprintf("MyError: %s (code: %d)", e.message, e.code) }
  1. Create instances of your error type: Now, you can create instances of your custom error type whenever an error occurs. You can set the appropriate values for each field to provide specific details about the error.
func SomeFunction() error { if err := SomeOtherFunction(); err != nil { return MyError{ message: "Something went wrong", code: 500, } } return nil }
  1. Use type assertions to handle specific error types: When handling errors, you can use type assertions to check if an error is of a specific type and access the additional information stored in the error.
err := SomeFunction() if err != nil { if myErr, ok := err.(MyError); ok { // Handle the specific error type fmt.Println("Error message:", myErr.message) fmt.Println("Error code:", myErr.code) } else { // Handle other error types fmt.Println("Unknown error:", err) } }

By creating structured error types, you can provide more context and information about the errors, making it easier to handle and debug them. Additionally, type assertions allow you to handle different error types differently, providing more granular error handling logic.