How to handle errors and exceptions in Go?

In Go, errors are considered first-class citizens and they are explicitly returned as a separate value from the function that can potentially raise the error. This allows for clean error handling and explicit control flow in the code.

Here are some approaches to handle errors and exceptions in Go:

  1. Return Error Values: Functions in Go commonly return an error as their last return value. It is a convention to return nil if there is no error and a non-nil value (usually of error type) if an error has occurred. The calling code can then check the error value and handle it accordingly.

Example:

func divide(a, b float64) (float64, error) { if b == 0 { return 0, fmt.Errorf("Cannot divide by zero") } return a / b, nil } result, err := divide(10, 0) if err != nil { // Handle the error } else { // Use the result }
  1. Custom Error Types: It is recommended to define custom error types that implement the error interface when dealing with specific errors in your code. This helps in distinguishing between different types of errors and providing additional information.

Example:

type MyError struct { message string } func (e *MyError) Error() string { return e.message } func myFunction() error { if condition { return &MyError{"Something went wrong"} } return nil }
  1. Panic and Recover: Go also provides a mechanism to handle exceptional conditions using the panic and recover functions. panic is used to terminate the normal flow of a Goroutine and triggers a stack unwinding until a recover is called to catch the panic. However, this approach should be used sparingly and only in situations where the program can no longer proceed safely.

Example:

func myFunction() { defer func() { if r := recover(); r != nil { log.Println("Recovered from panic:", r) } }() // Perform some operations if err != nil { panic(err) } }

It is important to note that Go emphasizes handling errors explicitly rather than relying on exceptions to handle error conditions. By doing so, it encourages a more controlled and predictable flow of code execution.