Control structures in Go

Control structures are useful in many ways. We use it to analyze variables and choose a direction to go in our program. Based on different criteria that is given as parameters we can make the program do different kind of things based on that.

Photo by Filip Mroz on Unsplash

Let us begin with the if statement

The if statement looks like the following below.

Note: The given variables x and y are not declared, by doing that i keep this code abstract as possible while explaining it.

if x > y {
// if x is bigger than y do this
}

and if the condition is not fulfilled we could also use the else statement on top of the if statement, example given below.

if x > y {
// if x is bigger than y do this
} else {
// x is not bigger than y, then do this instead

if the first condition isn’t fulfilled we could also add the else if statement to check another condition before the else statement is executed, example given below.

if x > y {
// if x is bigger than y do this
} else if x == y {
// x is equal to y
} else {
// none of the first conditions were true, then do this instead

Okey, I’ve now showed you a very simple usage of the if statement. We’ll now talk about how we can apply this type of control structure into our Go program and make it useful by also checking for errors when we call functions.

if err := file.Chmod(0664); err != nil {
log.Fatal(err)
}

In the example above, we use the shorthand assignment and declares a err variable assigned tofile.Chmod(0664) which is a function in the os package. The function Chmod returns an error and we check so the value returned isn’t equal to nil. You can read more about it here: https://golang.org/pkg/os/#Chmod

The example above is good by design, instead of writing it like the example below.

err := file.Chmod(0664)
if err != nil {
log.Fatal(err)
}

What about redeclaration and reassignment?

In Go we can redeclare an used variable within same the same scope, which basically means that we can do a legal duplicate of it and assign a new value to it. Example is given below, see how we make use of the err variable that is declared with a shorthand assignment in the beginning and then we use it again to reassign it to a new value that is returned by Stat() function.

f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}

For loop

Go only have one type of loop and that is the for loop. It can be done in three ways, the first one is given below. It takes an initialization, a condition and makes a variable change. for init; condition; post {}

for i := 0; i < 100; i++ { 
fmt.Println(i) // this for loop prints from 0 to 99
}

The second way of doing a for loop is like the following. for condition {} which is like the C language while. As long as the condition is true it will run.

for true { 
fmt.Println("Gopher")
}

The third way of looping with for is the following example. for {} 
It runs forever, basically it’s an infinite loop if you skip the condition statement. This type of for loop is very useful when you have to communicate and deal with multiple channels in Go.

for {
fmt.Println("Gopher")
}

By using the select statement inside of the for loop lets a goroutine wait on multiple communication operations. Example is given below. If you want to read more about goroutines and channels in go i recommend you these links below.

Goroutines: https://tour.golang.org/concurrency/1
Channels: https://tour.golang.org/concurrency/2

for {
select {
case job := <-jobChannel:
// do something with job
}
}

What about iterating on an array, slice, string and map or even reading from a channel?

In Go we use the range clause that manage the loop for us, awesome right.
It looks like the following below.

names := []string{"Henry", "Jessica", "Hannah"}
for key, value := range names {
fmt.Println(key," - ",value)
}

Maybe we don’t need the value in this case, fine. We only remove the value from the for so it looks like this.

names := []string{"Henry", "Jessica", "Hannah"}
for key := range names {
fmt.Println(key)
}

What if we only want to use the value? Then we only make sure to use the blank identifier which is an underscore “_”, this will tell the compiler to discard that value when we run our program. Example given below.

names := []string{"Henry", "Jessica", "Hannah"}
for _, value := range names {
fmt.Println(value)
}

Switch

Switch tries to match the value you switch on the different cases that are given, cases are evaluated from top to bottom and if there is no expression for the switch it will switch on true. Example given below.

x := 5

switch x {
case 2:
fmt.Println("x is equal to 2")
case 5:
fmt.Println("x is equal to 5")
default:
// default if nothing matches
}

Type switch

You can also use the switch to find out what the dynamic type of an interface variable is by doing following.

var t interface{}
switch t := t.(type) {
default:
// unexpected type
case bool:
// boolean
case int:
// integer
case *bool:
// pointer to boolean
case *int:
// pointer to integer
}