Anatomy of Conditional Statements and Loops in Go

Go provides if/else and switch conditional statements for code execution based on certain conditions. To execute some code over and over again, we have the for loop.

The if/else conditional statement

Go provides if, if-else, if-else if-else variants of if/else statement we are familiar with. It is used to check a condition, and execute some code when the condition is true or false.

package main

import "fmt"

func main() {
	condition := true

	if condition {
		fmt.Println("condition met")
	}

	fmt.Println("program terminated")
}

// condition met
// program terminated

Unlike JavaScript or C language, {} curly braces are mandatory even if there is only one statement between the {...}.

The if-else condition

In the case of if-else condition, if the if condition is false, it will execute the else block.

package main

import "fmt"

func main() {
	a := 2

	if a > 10 {
		fmt.Println("condition met")
	} else {
		fmt.Println("condition did not meet")
	}

	fmt.Println("program terminated")
}

// condition did not meet
// program terminated

One thing to notice here is that we have written else statement in the same line of ending brace } of the if statement. This is necessary because if we would have written else statement on a new line, Go would have put a semicolon ; at the end of if statement and program would have resulted in an error.

if condition {
}                   // implicit ;
else {
}

The if-else if-else condition

The else if condition is used when you want to try for multiple conditions.

package main

import "fmt"

func main() {
	fruit := "orange"

	if fruit == "mango" {
		fmt.Println("fruit is mango")
	} else if fruit == "orange" {
		fmt.Println("fruit is orange")
	} else if fruit == "banana" {
		fmt.Println("fruit is banana")
	} else {
		fmt.Println("I don't know which fruit this is")
	}
}

// fruit is orange

First if condition will be evaluated, if the condition meets (evaluated to true), code inside if block will be executed and no further conditions will be evaluated.

But if the if condition did not meet, the next conditions in succession of the else if blocks will be evaluated until one condition meets. If none of the conditions meet, else block will be evaluated.

Initial statement

You can execute an initial statement before if condition evaluates.

if statement; condition {
    ...
}

This can come in handy to initialize condition variable and restrict the scope of this variable to if-else block only.

package main

import "fmt"

func main() {
	if fruit := "banana"; fruit == "mango" {
		fmt.Println("fruit is mango")
	} else if fruit == "orange" {
		fmt.Println("fruit is orange")
	} else if fruit == "banana" {
		fmt.Println("fruit is banana")
	} else {
		fmt.Println("I don't know which fruit this is")
	}

	// fruit variable is unavailable here
	// fmt.Println(fruit)
}

// fruit is banana

Ternary condition

Go doesn’t support ternary one liners and there is no clear idiomatic way to achive that.

The switch conditional statement

The switch statement is generally used to replace multiple if-else conditions.

The syntax of the switch statement

The switch statement takes one input value and matches against many cases. Unlike C, Go doesn’t need a break statement to terminate the case block. case block will terminate as soon as the last statement in the case block executes and so is the switch statement. Duplicate cases (values) are not allowed in Go.

switch input {
    case value_1:
        ...
    case value_1:
        ...
}

Let’s look at a simple example of finding the finger name from the finger index.

package main

import "fmt"

func main() {
	finger := 2

	switch finger {
	case 1:
		fmt.Println("Thumb")
	case 2:
		fmt.Println("Index")
	case 3:
		fmt.Println("Middle")
	case 4:
		fmt.Println("Ring")
	case 5:
		fmt.Println("Pinky")
	}
}

// Index

In the above program, we are passing finger variable as an input value to switch block. Then switch try to find case block which matches that value. In the above program, since finger == 2, case 2 will be executed and logs the Index message in the terminal.

If finger value is not between 1-5, nothing will get printed.

The default case

Sometimes, we need else kind of condition where we need to execute some piece of code when none of the cases match the input value. In that case, default block is used.

package main

import "fmt"

func main() {
	finger := 6

	switch finger {
	case 1:
		fmt.Println("Thumb")
	case 2:
		fmt.Println("Index")
	case 3:
		fmt.Println("Middle")
	case 4:
		fmt.Println("Ring")
	case 5:
		fmt.Println("Pinky")
	default:
		fmt.Println("No fingers matched")
	}
}

// No fingers matched

In the above program, since the input finger value is 6 and none of the cases matches that value, the default block will be executed printing No fingers matched on the screen.

The default case does not have to be the last case. It can be anywhere in the switch block.

Multiple case values

You can present multiple (,) comma-separated case values to match the input switch value.

package main

import "fmt"

func main() {
	letter := "i"

	switch letter {
	case "a", "e", "i", "o", "u":
		fmt.Println("Letter is a vovel.")
	default:
		fmt.Println("Letter is not a vovel.")
	}
}

// Letter is a vovel.

The above program will print Letter is a vovel since variable letter has value i which belongs to case values "a", "e", "i", "o", "u".

The initial statement

There is another variant of switch statement where you can add initial statement before the input value just like if conditional statement.

switch statement; input {
 ...
}

Let’s see the previous example where in this case, we will define letter variable in the switch statement itself, restricting its scope to switch block.

package main

import "fmt"

func main() {
	switch letter := "i"; letter {
	case "a", "e", "i", "o", "u":
		fmt.Println("Letter is a vovel.")
	default:
		fmt.Println("Letter is not a vovel.")
	}
}

// Letter is a vovel.

Expressionless switch statement

Input value in Go’s switch statement is optional. When there is no input value to switch statement, case will be an expression that returns a boolean value.

package main

import "fmt"

func main() {
	number := 20

	switch {
	case number <= 5:
		fmt.Println("number is less than or equal to 5")
	case number > 5:
		fmt.Println("number is greater than 5")
	case number > 10:
		fmt.Println("number is greater than 10")
	case number > 15:
		fmt.Println("number is greater than 15")
	}
}

// number is greater than 5

Since number is greater than 20, number > 5 condition will meet and number is greater than 5 will be printed to the console.

We can use the initial statement without input value of switch statement. In the above program, we could initialize number variable in switch statement.

package main

import "fmt"

func getnumber() int {
	return 20
}

func main() {
	switch number := getnumber(); {
	case number <= 5:
		fmt.Println("number is less than or equal to 5")
	case number > 5:
		fmt.Println("number is greater than 5")
	case number > 10:
		fmt.Println("number is greater than 10")
	case number > 15:
		fmt.Println("number is greater than 15")
	}
}

// number is greater than 5

A semicolon is necessary after the initial statement because if we don’t add a semicolon, then our switch statement is no longer expressionless and number := getnumber() becomes the input value expression which is invalid.

The fallthrough statement

As normally, when a case block executes, no other cases are tried. In the above program, the number is greater than 5, 10 and 15 but since number > 5 and first case meets that condition and only that case block is executed. To execute another case blocks, we use fallthrough statement.

package main

import "fmt"

func main() {
	switch number := 20; {
	case number <= 5:
		fmt.Println("number is less than or equal to 5")
		fallthrough
	case number > 5:
		fmt.Println("number is greater than 5")
		fallthrough
	case number > 10:
		fmt.Println("number is greater than 10")
		fallthrough
	case number > 15:
		fmt.Println("number is greater than 15")
	}
}

// number is greater than 5
// number is greater than 10
// number is greater than 15

When a case condition is evaluated and returns true or matches the input value, that case block is executed. If the compiler finds fallthrough statement, the next case block is executed without even evaluating the case.

The fallthrough should be the last statement in a case block, else Go compiler will throw fallthrough statement out of place error.

fallthrough statement is not allowed in last case block as there is no further condition to fall into.

The for loops

Unlike C and other programming languages, the only available loop in Go is for loop. But many variants of for loop in Go will do all the jobs pretty well. So let’s get into it.

The for loop syntax

The for loop syntax consists of three statements and all three statements in Go are optional.

for init; condition; post {
    ...
}
  • init statement initializes any variables might be needed in condition check statement or post statement. This statement will be called once when for loop starts executing.
  • condition statement checks for a condition. If condition returns true, then the code inside for loop will execute.
  • At the end of code execution, post statement will be executed. In this statement, we can modify any variables defined in init statement. After the execution of post statement, condition statement will be evaluated again. If condition returns true, code inside for loop will be executed again else for loop terminates.

Let’s get started with the example.

package main

import "fmt"

func main() {
	for i := 1; i <= 6; i++ {
		fmt.Printf("Current number is %d \n", i)
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

In the above program, we are printing numbers from 1 to 6.

Variants of the for loop

As discussed earlier, all three statements in for loop are optional.

Optional post statement: We can drop post statement and execute inside for loop code to get the same results.

package main

import "fmt"

func main() {
	for i := 1; i <= 6; {
		fmt.Printf("Current number is %d \n", i)
		i++
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

Optional init statement

We can also drop init statement and execute outside for loop. But in this case, the variable i will be accessible outside the for loop.

package main

import "fmt"

func main() {
	i := 1
	for ; i <= 6; i++ {
		fmt.Printf("Current number is %d \n", i)
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

Optional init and post statement

We can only work with condition check statement. In this case, can drop all semicolons, Go will consider this statement as condition statement. This is like while loop in C language.


package main

import "fmt"

func main() {
	i := 1
	for i <= 6 { // ;i <= 6;
		fmt.Printf("Current number is %d \n", i)
		i++
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

Without all statements

As all for loop statements are optional, let’s see how that will work. A for loop without any statements is a for loop with condition statement being always true, hence it will loop infinitely unless terminated manually from inside the for loop code.

package main

import "fmt"

func main() {
	i := 1
	for {
		fmt.Printf("Current number is %d \n", i)

		if i == 6 {
			break
		}
		i++
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

Above code will print the same results as any of the previous examples, but this time we had to use break statement to terminate the loop, else it would have printed all the possible numbers.

The break statement

The break statement is used from inside the for loop to terminate the for loop. Any code after break statement will not execute.

package main

import "fmt"

func main() {
	for i := 1; i <= 10; i++ {
		if i > 6 {
			break
		}

		fmt.Printf("Current number is %d \n", i)
	}
}

// Current number is 1
// Current number is 2
// Current number is 3
// Current number is 4
// Current number is 5
// Current number is 6

In the above program, when i is greater than 6, if condition will be true and break statement will be executed. This will terminate the for loop immediately.

The continue statement

The continue statement is used to skip one for loop iteration. When for loop sees a continue statement, it simply ignores the current iteration, executes post statement and starts again. A simple example would be to print only even numbers between 1-10.

package main

import "fmt"

func main() {
	for i := 1; i <= 10; i++ {
		if i%2 != 0 {
			continue
		}

		fmt.Printf("Current number is %d \n", i)
	}
}

// Current number is 2
// Current number is 4
// Current number is 6
// Current number is 8
// Current number is 10

The return statement

If for loop encounters return statement, function execution will be stopped and the value will be returned by the function. Hence return is not particular to the for loop.

#golang #basics