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
If and else
What's similar to other languages:
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:
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
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.
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.
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.
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
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
// infinite loop
for {
fmt.Println("loop")
}
Optional update
for i := 0; i < 10; {
i++;
fmt.Println("loop")
}
Optional initialization
i:=0
for ; i < 10; i++ {
fmt.Println("loop")
}
Without initialization or update
i:=0
for ;i < 10; {
i++
fmt.Println("loop")
}
Don't even use the semicolons if its just a condition
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
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.
-
iis the index of the element in the slice -
vis the value of the element in the slice So the above construct will print0 1and1 3and2 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
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:
- When you want to close a file or database connection.
- Logging the end of a function.
- 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.
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:
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.
Top comments (0)