Control Flow and Functions
35 minControl flow statements determine the order of program execution. Go provides conditional statements (if-else, switch) for decision-making and loops (for) for repetition. Go's control flow is similar to C but with some differences: no parentheses around conditions, and `for` is the only loop construct (no while or do-while). Understanding control flow is fundamental to writing any Go program.
Functions are first-class citizens in Go—they can be assigned to variables, passed as arguments, and returned from other functions. Functions are declared with the `func` keyword. Go functions can return multiple values, which is idiomatic for returning results and errors. Functions enable code organization, reusability, and modularity. Understanding functions is essential for Go programming.
Go functions can return multiple values, which is commonly used to return a result and an error. The error handling pattern `result, err := function()` is idiomatic Go. Functions can have named return values, making code more readable. Functions can be variadic (accept variable number of arguments) using `...`. Understanding function features helps you write idiomatic Go code.
The `defer` statement schedules a function call to execute when the surrounding function returns. Deferred calls execute in LIFO (last-in-first-out) order. `defer` is commonly used for cleanup (closing files, unlocking mutexes). Deferred functions execute even if the function panics. Understanding `defer` helps you write code that properly cleans up resources.
Go's `for` loop is the only loop construct but is flexible. It can be used as a traditional for loop, while loop (omitting init and post), or infinite loop (omitting all parts). The `range` keyword iterates over arrays, slices, maps, strings, and channels. Understanding `for` loops enables you to implement any iteration pattern.
Best practices include using `defer` for cleanup, returning errors as the last return value, using named return values when they improve readability, keeping functions focused and small, and using `range` for iteration. Functions should be clear, focused, and handle errors properly. Understanding control flow and functions enables you to write effective Go programs.
Key Concepts
- Control flow statements (if, switch, for) determine execution order.
- Functions are first-class citizens in Go.
- Functions can return multiple values (commonly result and error).
- defer schedules functions to execute when the function returns.
- for is the only loop construct but is very flexible.
Learning Objectives
Master
- Using if-else and switch for conditional execution
- Creating and calling functions with multiple return values
- Understanding defer for resource cleanup
- Working with for loops and range for iteration
Develop
- Control flow and function design thinking
- Understanding Go's error handling patterns
- Writing idiomatic, maintainable Go code
Tips
- Use defer for cleanup (closing files, unlocking mutexes).
- Return errors as the last return value: func() (result Type, err error).
- Use range for iterating over slices, maps, and channels.
- Keep functions small and focused on a single responsibility.
Common Pitfalls
- Not handling errors returned from functions.
- Not understanding defer execution order (LIFO).
- Using for loops when range would be simpler.
- Creating functions that are too long or do too many things.
Summary
- Control flow statements determine program execution order.
- Functions are first-class citizens enabling flexible code organization.
- Multiple return values enable idiomatic error handling.
- defer ensures proper resource cleanup.
- Understanding control flow and functions is fundamental to Go.
Exercise
Create functions with different parameter types and return values.
package main
import "fmt"
// Simple function
func greet(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}
// Function with multiple return values
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// Function with named return values
func getPerson() (name string, age int, city string) {
name = "Alice"
age = 25
city = "Boston"
return // naked return
}
// Function with defer
func processFile(filename string) {
fmt.Printf("Opening file: %s
", filename)
defer fmt.Printf("Closing file: %s
", filename)
fmt.Printf("Processing file: %s
", filename)
}
func main() {
// If-else statements
age := 18
if age >= 18 {
fmt.Println("Adult")
} else {
fmt.Println("Minor")
}
// Switch statement
day := "Monday"
switch day {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("Weekday")
case "Saturday", "Sunday":
fmt.Println("Weekend")
default:
fmt.Println("Unknown day")
}
// Function calls
message := greet("Go Developer")
fmt.Println(message)
// Multiple return values
result, err := divide(10, 2)
if err != nil {
fmt.Printf("Error: %v
", err)
} else {
fmt.Printf("Result: %.2f
", result)
}
// Named return values
name, age, city := getPerson()
fmt.Printf("Person: %s, %d years old, from %s
", name, age, city)
// Defer example
processFile("data.txt")
}