Control Flow
## Learning Objectives
- Master if, else if, else statements
- Understand switch statements
- Learn for loops and variants
- Use defer for cleanup
## if Statement
### Basic if
```go
age := 18
if age >= 18 {
fmt.Println("Adult")
}
```
### if-else
```go
age := 15
if age >= 18 {
fmt.Println("Adult")
} else {
fmt.Println("Minor")
}
```
### if-else if-else
```go
score := 85
var grade string
if score >= 90 {
grade = "A"
} else if score >= 80 {
grade = "B"
} else if score >= 70 {
grade = "C"
} else if score >= 60 {
grade = "D"
} else {
grade = "F"
}
fmt.Println("Grade:", grade)
```
### With Initialization
```go
if err := doSomething(); err != nil {
fmt.Println("Error:", err)
return
}
```
## switch Statement
### Basic switch
```go
day := 3
var dayName string
switch day {
case 1:
dayName = "Monday"
case 2:
dayName = "Tuesday"
case 3:
dayName = "Wednesday"
case 4:
dayName = "Thursday"
case 5:
dayName = "Friday"
case 6:
dayName = "Saturday"
case 7:
dayName = "Sunday"
default:
dayName = "Invalid"
}
fmt.Println(dayName)
```
### Multiple Values
```go
month := 4
var days int
switch month {
case 1, 3, 5, 7, 8, 10, 12:
days = 31
case 4, 6, 9, 11:
days = 30
case 2:
days = 28
default:
days = 0
}
```
### No Expression
```go
num := 10
switch {
case num < 0:
fmt.Println("Negative")
case num == 0:
fmt.Println("Zero")
case num > 0:
fmt.Println("Positive")
}
```
### fallthrough
```go
score := 75
var grade string
switch {
case score >= 90:
grade = "A"
case score >= 80:
grade = "B"
case score >= 70:
grade = "C"
fallthrough // Continues to next case
case score >= 60:
grade = "D"
default:
grade = "F"
}
```
## for Loop
### Basic for
```go
for i := 0; i < 5; i++ {
fmt.Println(i) // 0, 1, 2, 3, 4
}
```
### Alternative Syntax
```go
i := 0
for i < 5 {
fmt.Println(i)
i++
}
```
### Infinite Loop
```go
for {
fmt.Println("Forever")
if done {
break
}
}
```
### Range Loop
```go
nums := []int{1, 2, 3, 4, 5}
for i, v := range nums {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
// Ignore index
for _, v := range nums {
fmt.Println(v)
}
// Index only
for i := range nums {
fmt.Println(i)
}
```
### String Iteration
```go
str := "Hello"
for i, r := range str {
fmt.Printf("Index: %d, Rune: %c\n", i, r)
}
```
### Map Iteration
```go
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
for key, value := range ages {
fmt.Printf("%s: %d\n", key, value)
}
```
### Channel Iteration
```go
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch {
fmt.Println(v)
}
```
## while Equivalent
Go has no `while` keyword. Use `for` without initialization and post statement.
```go
n := 1
for n < 100 {
n *= 2
}
fmt.Println("Result:", n)
```
## break and continue
### break - Exit Loop
```go
for i := 0; i < 10; i++ {
if i == 5 {
break // Exit when i is 5
}
fmt.Println(i) // 0, 1, 2, 3, 4
}
```
### continue - Skip Iteration
```go
for i := 0; i < 5; i++ {
if i == 2 {
continue // Skip when i is 2
}
fmt.Println(i) // 0, 1, 3, 4
}
```
### Labeled break
```go
outer:
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
if j == 2 {
break outer // Breaks outer loop
}
fmt.Printf("(%d,%d) ", i, j)
}
}
fmt.Println()
```
## Nested Loops
```go
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf("(%d,%d) ", i, j)
}
fmt.Println()
}
// Output:
// (0,0) (0,1) (0,2)
// (1,0) (1,1) (1,2)
// (2,0) (2,1) (2,2)
```
## defer
### Basic defer
```go
func readFile(filename string) {
file, err := os.Open(filename)
if err != nil {
return
}
defer file.Close() // Executes when function returns
// Read file...
}
```
### Multiple defers
```go
func example() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
}
fmt.Println("Main")
// Output: Main, 3, 2, 1 (LIFO order)
```
### defer with Arguments
```go
func example() {
x := 10
defer fmt.Println("Deferred:", x) // Prints 10, not 20
x = 20
fmt.Println("Main:", x)
}
// Output: Main: 20, Deferred: 10
```
### Common Uses
```go
// Unlock mutex
mu.Lock()
defer mu.Unlock()
// Close database connection
db, err := sql.Open(...)
defer db.Close()
// Print function entry/exit
func trace(name string) {
fmt.Println("Entering:", name)
defer fmt.Println("Exiting:", name)
}
```
## return Statements
### Named Return Values
```go
func rectangleProperties(width, height float64) (area, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // Naked return
}
```
### Early Return
```go
func findItem(items []int, target int) int {
for i, item := range items {
if item == target {
return i // Early return when found
}
}
return -1 // Not found
}
```
## goto Statement
### Using goto
```go
func example() {
for i := 0; i < 5; i++ {
if i == 3 {
goto done
}
fmt.Println(i)
}
done:
fmt.Println("Finished")
}
```
## Common Patterns
### Sum 1 to N
```go
sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
fmt.Println("Sum:", sum)
```
### Find in Slice
```go
nums := []int{3, 7, 2, 9, 4}
target := 9
for i, num := range nums {
if num == target {
fmt.Println("Found at index:", i)
break
}
}
```
### Count Matches
```go
nums := []int{1, 2, 3, 2, 4, 2, 5}
target := 2
count := 0
for _, num := range nums {
if num == target {
count++
}
}
fmt.Println("Count:", count)
```
### Fibonacci
```go
a, b := 0, 1
for i := 0; i < 10; i++ {
fmt.Print(a, " ")
a, b = b, a+b
}
```
## Summary
- if/else if/else for conditional logic
- switch for multiple discrete values (with multiple cases)
- for is the only loop keyword in Go
- range loops iterate over slices, maps, strings, channels
- break exits loop; continue skips iteration
- defer executes code when function returns (LIFO order)
- Use labeled break for nested loop control
- goto is available but use sparingly
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →