Error Handling Patterns
Error Handling Fundamentals
Error handling in Go is a critical aspect of writing robust and reliable software. This section explores various patterns and techniques for managing errors effectively.
Common Error Handling Strategies
1. Explicit Error Checking
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
// File processing logic
return nil
}
2. Error Propagation
func validateAndProcess(data string) error {
if err := validate(data); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := process(data); err != nil {
return fmt.Errorf("processing error: %w", err)
}
return nil
}
Error Flow Visualization
graph TD
A[Function Call] --> B{Error Occurred?}
B -->|Yes| C[Log Error]
B -->|No| D[Continue Execution]
C --> E[Return Error]
C --> F[Handle/Recover]
E --> G[Caller Handles Error]
Advanced Error Handling Techniques
Error Type Assertion
func handleSpecificError(err error) {
switch e := err.(type) {
case *ValidationError:
fmt.Println("Validation Error:", e.Message)
case *NetworkError:
fmt.Println("Network Error:", e.Reason)
default:
fmt.Println("Unknown error:", err)
}
}
Error Handling Patterns Comparison
Pattern |
Use Case |
Complexity |
Recommended |
Simple Checking |
Basic errors |
Low |
Always |
Error Wrapping |
Adding context |
Medium |
Recommended |
Custom Error Types |
Specific scenarios |
High |
Selective |
Panic and Recover Mechanism
func safeExecute(fn func()) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
fn()
}
Best Practices
- Always check and handle errors
- Use error wrapping for context
- Create meaningful custom error types
- Avoid silent error suppression
- Log errors for debugging
Error Handling in Concurrent Contexts
func processItems(items []string) error {
errChan := make(chan error, len(items))
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item string) {
defer wg.Done()
if err := processItem(item); err != nil {
errChan <- err
}
}(item)
}
go func() {
wg.Wait()
close(errChan)
}()
for err := range errChan {
return err
}
return nil
}
At LabEx, we emphasize mastering these error handling patterns to create more reliable and maintainable Go applications.