Practical Usage Patterns
Common Multi-Return Function Scenarios
Error Handling Pattern
func fetchUserData(userID int) (User, error) {
user, err := database.Find(userID)
if err != nil {
return User{}, fmt.Errorf("user not found: %v", err)
}
return user, nil
}
func main() {
user, err := fetchUserData(123)
if err != nil {
log.Printf("Error: %v", err)
return
}
// Process user data
}
Validation and Status Return
func validateInput(data string) (bool, string, error) {
if len(data) == 0 {
return false, "", errors.New("empty input")
}
if len(data) > 100 {
return false, "too long", nil
}
return true, "valid", nil
}
Advanced Usage Patterns
Multiple Return Value Processing
graph TD
A[Function Call] --> B{Check Multiple Returns}
B --> |Validate| C[Process Results]
B --> |Error| D[Handle Error]
Concurrent Operation Patterns
func fetchMultipleResources() ([]Data, []Error, time.Duration) {
start := time.Now()
var (
results []Data
errors []Error
mu sync.Mutex
)
// Concurrent processing
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
defer wg.Done()
data, err := fetchResource1()
mu.Lock()
if err != nil {
errors = append(errors, err)
} else {
results = append(results, data)
}
mu.Unlock()
}()
// Similar goroutines for other resources
wg.Wait()
return results, errors, time.Since(start)
}
Practical Patterns Table
Pattern |
Description |
Use Case |
Error Handling |
Return value + error |
Database operations |
Validation |
Boolean + message |
Input validation |
Complex Results |
Multiple typed returns |
Concurrent processing |
graph LR
A[Multi-Return Function] --> B[Memory Allocation]
B --> C[Performance Impact]
C --> D[Optimization Strategies]
- Use named return values
- Minimize allocations
- Reuse return value structs
- Consider single struct returns
LabEx Recommended Practices
type Result struct {
Data interface{}
Success bool
Error error
}
func complexOperation() Result {
// Flexible return pattern
return Result{
Data: processedData,
Success: true,
Error: nil,
}
}
Error Handling Strategy
func safeOperation() (Result, error) {
defer func() {
if r := recover(); r != nil {
// Handle panic
}
}()
// Complex operation
return processData()
}
Key Takeaways
- Use multi-return for clear, expressive code
- Implement consistent error handling
- Balance between complexity and readability
- Consider performance implications
By mastering these practical patterns, developers can write more robust and efficient Go applications with multi-return functions.