Go Basics: Flow control
Tags: go, programming, beginners, codenewbie
Published: 2021-12-09 06:46:24

## Flow Control

In the last article, we saw how to use functions. We also saw a preview of the `for` loop. We will explore the flow control syntax in depth in this article.

Go has the following flow control mechanisms:
- `if/else` 
- `switch` 
- `for` 
- `defer` 

If you are familiar with other languages, `defer` might be new to you and you may be missing `while` loops in this list.

Let's look at the syntax of each one of them.

### Contents
1. [If/else](#if-and-else)
2. [Switch](#switch)
3. [For](#for-loops)
4. [Defer](#defer)

### If and else

What's similar to other languages:
```go
if condition {
    // execute if condition is true
} else if condition {
    // execute if first condition is false but the second is true
} else {
    // execute if both conditions are false
}
```
Notice that there are no braces around the conditions.

What's different from other languages:
```go
if a:=rand.Intn(2); a==1 {
    return a
}  else {
	return a+1
}
```
You can declare a variable before the condition and use it in the condition or in the if/else blocks.

### Switch
Switch in Go is much more powerful than in other languages. 

**A simple swtich/case**
```go
switch a {
case 1:
    fmt.Println("a is 1")
case 2:
    fmt.Println("a is 2")
default:
    fmt.Println("a is neither 1 nor 2")
}
```
The `switch` statement is used to execute different blocks of code depending on the value of a variable. Again, no braces around the value.
And if you've been coding in other languages (like Java), having no `break` must be a welcome change. There is no fall through in Go and only the first matching case is executed.

**More flexible switch/case**
Just like if/else, you can also declare a variable before the switch and use it in the switch/case blocks.
```go
switch a := rand.Intn(10); a {
case 0, 1, 2, 3, 4:
    fmt.Println("a is 0, 1, 2, 3 or 4")
case 5, 6, 7, 8, 9:
    fmt.Println("a is 5, 6, 7, 8 or 9")
default:
    fmt.Println("a is neither 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9")
}
```
Also notice how a case can be matched with multiple values. In Java, this was achieved with fall through.

**Not just integers**
You can also use switch case with strings, other types, and even expressions.
```go
switch name {
case "John", "Paul", "George", "Ringo":
    fmt.Println("str is one of John, Paul, George or Ringo")
}

//switch/case with expression
switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
    fmt.Println("It's the weekend")
default:
    fmt.Println("It's a weekday")
}
```
This means that now you can use the `switch` statement for any type. Also notice that `default` is not mandatory.

**Switch without a condition**
You can also use the `switch` statement without a condition. Rather you can put your condition in the `case` block.
```go
switch {
case a > b:
    fmt.Println("a is greater than b")
case a < b:
    fmt.Println("a is less than b")
default:
    fmt.Println("a is equal to b")
}
```
This makes `switch` even more powerful because this construct is similar to else if ladders. 
However, it does not give a performance boost because it will not use a jump table. It is only good for readability.

### For loops
We saw an example of the `for` loop in the last article. Now let's look closer at the syntax.

**A simple for**
```go
for i := 0; i < 10; i++ {
    fmt.Println(i)
}
```
The `for` loop is used to execute a block of code a number of times. The above construct has almost no difference from the `for` loop in other languages.
The only difference is the shorthand variable declaration of the loop variable. I'm sure you are an expert with the shorthand variable declaration by now. It's everywhere.

**All parts of the looping construct are optional**

Infinite loops
```go
// infinite loop
for {
    fmt.Println("loop")
}
```

Optional update
```go
for i := 0; i < 10; {
	i++;
    fmt.Println("loop")
}
```

Optional initialization
```go
i:=0
for ; i < 10; i++ {
    fmt.Println("loop")
}
```

Without initialization or update
```go
i:=0
for ;i < 10; {
	i++
    fmt.Println("loop")
}
```

Don't even use the semicolons if its just a condition
```go
i:=0
for i<10 {
    i++
    fmt.Println("loop")
}
```

Wait a minute, isn't this a while loop? - **YES** 

And that's why there is no explicit `while` loop in Go.


**for with range**
```go
for i, v := range []int{1, 3, 5} {
    fmt.Println(i, v)
}
```
The `range` statement is used to iterate over a slice or map. Here we iterate over a slice of integers. 
We will look into the array syntax later but for now focus on the variables. 
- `i` is the index of the element in the slice
- `v` is the value of the element in the slice
So the above construct will print `0 1` and `1 3` and `2 5`.

That's it about the `for` loop. Let's move on to something new now.

### defer
The `defer` statement is used to execute a block of code at the end of the function. 
This is sometimes called a "last resort" or "finalizer" because it is executed after the function returns.

**A simple defer**
```go
func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}
```
The above example will print `hello` and then `world` at the end of the function. It does not matter where the `defer` statement is placed. It will always be executed at the end of the function.

This must be a little strange but it is useful in many scenarios. For example:
1. When you want to close a file or database connection.
2. Logging the end of a function.
3. Logging what values a variable has at the end of a function.

There are many other examples of `defer` in the Go language. You can read more about it [here](https://blog.golang.org/defer-panic-and-recover).

One point worth mentioning is that the `defer` statement is executed in LIFO order. If you have multiple `defer` statements, the last one will be executed first.
Let's see an example:
```go
func main() {
    fmt.Println("counting")
    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }
    fmt.Println("done")
}
```
This will print `counting` and then `done` and then `9` and then `8` and so on. Similar to a stacktrace.

---


This should give you an idea about flow control in Go. In the next article, I will cover more syntactical elements of Go.

Thanks for reading. If you want to connect with me, you can find me on Twitter [@abh1navv](https://twitter.com/abh1navv).