LanguagesUnderstanding Control Structures in Go

Understanding Control Structures in Go

Go Programming ``

In any programming language, control structures help in forming the important building blocks of the programming logic. Therefore, a clear understanding of its syntaxes is a basic requirement. Someone familiar with C/C++ will find many similarities in the control structures provided by Go in general. But note that Go has brought forth some new ideas to the table. This article glimpses into the use of control structure in Go programming.

Control Structures in Golang

The control structures provide the means to control or manipulate the flow of the program. Imagine a down flowing stream of water; we can meander its route through a curved path or maybe create a loop through which water may pass. We, however, cannot change its downward flow, but in between the beginning and the end of the stream, we can play with its route or control the flow. Similarly, the control structures in Go, such as if conditions, for loops, switch statements, and so forth, help in controlling the flow of the program. The beginning and end – or termination – of the program cannot be changed, for a program that starts execution must eventually stop somewhere. The control structures simply control the flow of the program in between start and stop.

Programs are nothing but manifestations of an algorithm, and an algorithm is the logical explanation you provide in pursuit of solving a specific problem. Syntactically, in programming languages such as Go, this control structure actually helps in disseminating the logic to solve a problem. Typically there are three types of control structures we find in any programming language. They are:

  • Sequential flow
  • Conditional flow
  • Iterative flow

Read: Understanding Mathematical Operators in Go

Sequential Flow Control Structure in Go

Sequential flow is the simplest control structure in Go and follows a straight path. Imagine a straight flowing downward stream of water. In programming, instructions are executed one after another in an obvious sequence. Also, while it may seem a very elementary pattern, many complex algorithms are expressed in this way and modules of code are actually executed in a numbered fashion. Consider the following:

Example:
Statement 1
Statement 2
Statement 3
Statement 4
Statement 5

Conditional Flow Control Structure in Go

Conditional flows are best viewed as a choice to pick one from another. At some point of the code flow, we have to decide a specific path. The logic is expressed in such a way that the result or outcome of the code varies as one path is chosen over another. There can be one or multiple conditions based upon which the flow of the code changes direction. Imagine a junction of a road where we have to decide which way to go. Consider the following pseudo code:

Example:
If  Then:
	Statement 1
Else If  then:
	Statement 2
...
Else
	Statement 5
End If

Iterative Flow Control Structures in Go

Iterative flow employs the logic of loops. Here, there is a single entry point based upon certain conditions, which executes the statements within the iterative block. At every iterative step, it checks the condition to see whether it is still satisfied or not and only breaks out of the loop at the step when the condition is no longer satisfied – or returns a Boolean <false. So there is a single entry and exit point and in-between there are one or more repetitive statements. It is a merry-go-round of programming where the control enters at a point, repetitively does certain tasks, and breaks out of it at another specific point. Consider the following example:

Example:
For I = 1 To N
	Statement 1
	...
	Statement 5
	I = I + 1
End For

Read: How to Use Strings in Go

Sequential Flow Code Example in Go

A simple illustration of a sequential flow is to write a program that counts natural numbers 1 to 10 and prints each one in its own line. The code in Go would be something like this:

package main
import “fmt”
func main() {
	fmt.Println(1)
	fmt.Println(2)
	fmt.Println(3)
	fmt.Println(4)
	fmt.Println(5)
	fmt.Println(6)
	fmt.Println(7)
	fmt.Println(8)
	fmt.Println(9)
	fmt.Println(10)
}

Or we could write the following Go code instead:

	fmt.Println(`1
2
3
4
5
6
7
8
9
10`)

This latter syntax is very typical of Go and cannot be found in C/C++, although look-wise, they may seem a distant brother to each other.

In any case, the flow of the code is sequential. Also note that this type of code is tedious; imagine if the numbers are huge – then writing a single line each time we need to print is not a very efficient way to code. In fact, it can be better expressed through an iterative flow of code.

Iterative Flow Code Example in Go

The iterative flow in Go is realised through a for statement. It allows repetitive execution of a block of code. So if we rewrite the above code, it will look like this:

package main
import “fmt”
func main() {
	for i := 1; i <= 10; i++ {
		fmt.Println(i)
	}
}

Observe how the for loop begins by initiating a value i:=1 to begin the iteration, then the control flow checks the condition, and, if it is satisfied, enters into the loop and executes the fmt.Println(i) statement. After printing once, the control goes to the increment section of the loop – the i++ statement – and again checks if the condition i<=10 satisfied or not. If it is satisfied, the block of code inside the for loop is executed, then again goes to the i++ section and the condition section of the for loop. This is repeated until the condition is no longer satisfied and eventually breaks out of the loop. To put it categorically:

Step 1: Initialize a variable (i:=1 in our case);
Step 2: Conditional expression (i<=10) which is either true or false;
Step 3: Expression (i++, increment in our case)
Step 4: Block of code to execute if the outcome of the condition statement (step 2 ) is true. Otherwise break from the for loop.
Step 5: Repeat the order: step 3 then step 2 and step 4.

If you are familiar with the C/C++ looping statements, they are of three types: for, while and do…while. Though there are subtleties of convenience in using any one of the three, it is but a choice among equal capability. This confusion of choice is totally discarded in Go and provides only one type, that is, the for loop. Go uses two kinds of syntaxes for statements: a plain for statement (as we have seen) another one is the for … range statement. Here is a quick example of how to use for … range in Go:

package main
import (
	"fmt"
	"unicode"
)

func main() {
    greetings := "Hello! friends"
	for index, ch := range greetings {
		fmt.Printf("%c ", unicode.ToUpper(ch))
		index++
	}
}

Read: Arrays and Slices in Go

Conditional Flow Code Example in Go

As we can see that the for loop has a conditional expression, which acts as an entry keeper but there are statements that decide the flow of code based upon a given condition. The if-statements do this. Let us modify the program of printing 1-10 numbers and print odd or even based upon a condition:

func main() {
	for i := 1; i <= 10; i++ {
		if i%2 == 0 {
			fmt.Println(i, "is EVEN")
		} else {
			fmt.Println(i, "is ODD")
		}
	}
}

If a number is ODD or EVEN is decided by the expression i%2. If the number divided by 2 and has a 0 remainder, the number is EVEN otherwise it is ODD. Now, based upon whether the outcome of the conditional statement i%2 == 0 is true or false, the execution path of the code is altered. Of course, we can have multiple/nested if..else statements as follows:

if i%2 == 0 {
	// do something
} else if i%3 == 0{
	//do something
} else if i%5 == 0{
	//do something
} else if i%9 == 0{
	//do something
}else {
	//do something
}

The point is that the conditional statements can change the flow of the control as per the outcome of a condition.
Sometimes multiple if…else conditional statements are an inconvenient way to write a code. Instead we can write Go switch statements to harness the flow of the code, as shown here:

num := 10
switch {
case num < 100: fmt.Println("Less than 100") case num > 100:
	fmt.Println("greater than 100")
default:
	fmt.Println("equal to 100")
}

Here is another example of a switch statement in Go:

package main
import (
	"fmt"
	"math/rand"
	"time"
)

func main() {

	deck := []string{"spade", "heart", "club", "diamond"}
	cards := []string{"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"}
	randIndex := rand.New(rand.NewSource(time.Now().UnixNano()))
	switch d := deck[randIndex.Intn(4)]; d {
	case "spade":
		fmt.Println(cards[randIndex.Intn(13)], "SPADE")
	case "club":
		fmt.Println(cards[randIndex.Intn(13)], "CLUB")
	case "heart":
		fmt.Println(cards[randIndex.Intn(13)], "HEART")
	case "diamond":
		fmt.Println(cards[randIndex.Intn(13)], "DIAMOND")
	default:
		fmt.Println("OOPS!!")
	}
}

Final Thoughts on Control Structures in Go

So there are three basic control structures in Go: a simple sequential flow, for loops for iterative flow and if conditions and switch statements. In fact, these three suffice the need of the programmer. Unlike C/C++, Go trimmed the syntaxes to the point of need rather than having too many options. However, Go is still a toddler and has miles to go even to be compared to C/C++. However, it is worth mentioning that programmers like simplicity and Go aptly provides it. Perhaps this is one of the biggest reasons for its popularity.

Read: How to Handle Errors in Go

Latest Posts

Related Stories