DEV Community

Cover image for Flow Control Statements in Go
Ali Farhadnia
Ali Farhadnia

Posted on • Originally published at alifarhadnia.com

3

Flow Control Statements in Go

Flow control statements are the backbone of any programming language, and Go is no exception. They allow developers to dictate the execution flow of their programs, enabling decision-making, looping, and resource management. In this article, we’ll dive deep into Go’s flow control statements, including for, if, switch, and defer, and explore how they can be used effectively in your Go programs.

This article is part of a series of tutorials aimed at helping developers deepen their understanding of Go. Whether you're a beginner or an experienced developer, this guide will provide you with the knowledge you need to write more efficient and readable Go code.

By the end of this article, you’ll have a solid understanding of:

  • The different types of flow control statements in Go.
  • How to use these statements in real-world scenarios.
  • Best practices and common pitfalls to avoid.

Let’s get started!

Core Concepts

1. The for Loop

The for loop is Go’s only looping construct, but it’s incredibly versatile. It can be used in several ways:

Basic for Loop

for i := 0; i < 10; i++ {
    fmt.Println(i)
}
Enter fullscreen mode Exit fullscreen mode

This is the traditional for loop, where you initialize a variable, set a condition, and increment the variable.

for Continued (While-like Loop)

Go doesn’t have a while keyword, but you can achieve the same effect using for:

sum := 1
for sum < 1000 {
    sum += sum
}
fmt.Println(sum)
Enter fullscreen mode Exit fullscreen mode

This loop continues as long as the condition sum < 1000 is true.

Forever Loop

If you omit the condition, the for loop runs forever:

for {
    fmt.Println("Infinite loop")
}
Enter fullscreen mode Exit fullscreen mode

This is useful for tasks that need to run continuously, like servers.

2. The if Statement

The if statement is used for conditional execution.

Basic if Statement

if x > 10 {
    fmt.Println("x is greater than 10")
}
Enter fullscreen mode Exit fullscreen mode

if with a Short Statement

You can execute a short statement before the condition:

if x := 5; x < 10 {
    fmt.Println("x is less than 10")
}
Enter fullscreen mode Exit fullscreen mode

if and else

You can also use else and else if:

if x > 10 {
    fmt.Println("x is greater than 10")
} else if x == 10 {
    fmt.Println("x is equal to 10")
} else {
    fmt.Println("x is less than 10")
}
Enter fullscreen mode Exit fullscreen mode

3. The switch Statement

The switch statement is a powerful way to handle multiple conditions.

Basic switch

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X")
case "linux":
    fmt.Println("Linux")
default:
    fmt.Printf("%s.\n", os)
}
Enter fullscreen mode Exit fullscreen mode

Switch Evaluation Order

Go evaluates switch cases from top to bottom, stopping when a case succeeds.

Switch with No Condition

A switch with no condition is the same as switch true:

t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("Good morning!")
case t.Hour() < 17:
    fmt.Println("Good afternoon.")
default:
    fmt.Println("Good evening.")
}
Enter fullscreen mode Exit fullscreen mode

4. The defer Statement

The defer statement postpones the execution of a function until the surrounding function returns.

Basic defer

func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}
Enter fullscreen mode Exit fullscreen mode

Output:

hello
world
Enter fullscreen mode Exit fullscreen mode

Stacking defers

Deferred functions are executed in LIFO order:

func main() {
    defer fmt.Println("first")
    defer fmt.Println("second")
    defer fmt.Println("third")
}
Enter fullscreen mode Exit fullscreen mode

Output:

third
second
first
Enter fullscreen mode Exit fullscreen mode

Practical Example

Let’s walk through a real-world example that demonstrates the use of these flow control statements. We’ll create a simple program that processes a list of tasks and prints their status.

package main

import (
    "fmt"
    "time"
)

type Task struct {
    Name     string
    Complete bool
}

func main() {
    tasks := []Task{
        {"Write blog post", false},
        {"Review PRs", true},
        {"Deploy service", false},
    }

    for i, task := range tasks {
        fmt.Printf("Processing task %d: %s\n", i+1, task.Name)
        if task.Complete {
            fmt.Println("Task is already complete.")
        } else {
            fmt.Println("Task is incomplete. Completing now...")
            time.Sleep(1 * time.Second) // Simulate task completion
            task.Complete = true
            fmt.Println("Task completed.")
        }
    }

    switch time.Now().Weekday() {
    case time.Saturday, time.Sunday:
        fmt.Println("It's the weekend! Time to relax.")
    default:
        fmt.Println("It's a weekday. Back to work!")
    }

    defer fmt.Println("All tasks processed.")
}
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Explanation

  1. Task Struct: We define a Task struct with Name and Complete fields.
  2. Task List: We create a slice of Task objects.
  3. for Loop: We iterate over the tasks using a for loop. For each task, we check if it’s complete using an if statement.
  4. switch Statement: We use a switch statement to check if it’s the weekend or a weekday.
  5. defer Statement: We use defer to print a message after all tasks are processed.

Best Practices

  1. Use for Loops Wisely: Since Go only has for loops, make sure to use them appropriately. Avoid infinite loops unless necessary.
  2. Keep if Statements Simple: Use short statements in if conditions to keep your code clean and readable.
  3. Leverage switch for Multiple Conditions: switch statements are more readable than multiple if-else statements when handling multiple conditions.
  4. Use defer for Cleanup: defer is great for resource cleanup, like closing files or releasing locks.
  5. Avoid Deep Nesting: Deeply nested if or for statements can make your code hard to read. Consider refactoring into functions.

Conclusion

Flow control statements are essential tools in Go that allow you to control the execution flow of your programs. By mastering for, if, switch, and defer, you can write more efficient, readable, and maintainable Go code.

I encourage you to try out the example provided in this article and experiment with these concepts on your own.

Call to Action

This article is part of a Go Tutorial Series aimed at helping you become a more proficient Go developer. If you found this article helpful, be sure to check out the previous and upcoming tutorials in this series. Check it out on my Blog or Dev.to.

Happy coding! 🚀

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs