Sage-Code Laboratory
index<--

Go: Control Flow

Control flow is a group of statements used to control execution of statements. Normally a program is linear. That is statements are executed in order top down, step by step until the end of file. Using control statements we can make code branches, loops and selections.

Decision Statement

Go like any other languages has the "if" statement. This is using a conditional expression to create a fork in the program. When the conditional value is true the next statement or a group of statements is executed, otherwise is not executed and skipped.

condition

Conditional Execution


Example:

Example of decision with a single block.

//file conditional_branch.go
package main

import (
	"fmt"
	"math"
)

func sqrt(x float64) string {
	if x < 0 {
		return sqrt(-x) + "i"
	}
	return fmt.Sprint(math.Sqrt(x))
}

func main() {
	fmt.Println(sqrt(2), sqrt(-4))
}

Note: The conditional expression do not have to be included in parentheses (...) in contrast to JavaScript and C. After the expression we use braces {...} that are mandatory to create the block of code associated with the decision statement.

Local Scope

The "if" statement has a local scope. That is we can define a local "control variable" to be used inside the if block. That is unusual for a programming language. In the next example variable v is in to local scope of the "if" statement. Variables declared by the statement are only in scope until the end of the "if". If we try using v after the last return statement we will have an error.

Example of local scope variables:

//file if_scope.go
package main

import (
	"fmt"
	"math"
)

// declare local v using type inference
func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

Two branches

For creation of two blocks of code in decision statement we use the "else" keyword. This is also known as two ways conditional statement. Local variables declared using "if" statement are available in both branches, as expected.

decision

Two ways Decision


Example:

//file two_ways.go
package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
    // Two ways decision with local variable "v"
    if v := math.Pow(x, n); v < lim {
        return v
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // can't use v here, it's gone
    return lim
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}

Iteration

Go use only one keyword for all iterations: the "for" keyword. This can define a finite or infinite loop.

Basic loop

The basic "for loop" has three components separated by semicolons:

  1. the init statement: executed before the first iteration
  2. the condition expression: evaluated before every iteration
  3. the post statement: executed at the end of every iteration
classic-for

Iteration Diagram

Notes: The "init" statement will often be a short variable declaration, and the variables declared there are visible only in the scope of the for statement. After every iteration, the "post" statement will be executed. The loop will stop iterating once the condition evaluates to false.

Example:

Next example will sum all numbers from 0 to 9. The result should be 50.

//file iteration.go
package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum)
}

Notes:: Unlike other languages Go, or Golang there are no parentheses surrounding the three components of the for statement. However the braces {...} for the block are always required. The "init" and "post" statement are optional.

The While Loop

Go, do not have "while" statement. This may be a surprise, but we can emulate the use-case of "while" by using the "for" statement with conditional but no "init" and no "post" statements.

while loop

While Loop


Example:

Example of for with no "init: and no "post". It may be curios how the single semicolon is still necessary. So it looks like a conditional between two semicolons. That is what learning Go is all about. Be careful to details, don't let yourself intimidated.

//file while_loop.go
package main

import "fmt"

func main() {
	sum := 1
	for ;sum < 1000; {
		sum += sum
	}
	fmt.Println(sum)
}

Infinite loop

To simulate an infinite iteration we use a for loop with no condition and no control variable. Infinite loops are evil. You must avoid making an infinite loop at all cost. You must use a breack or exit condition, otherwise your stoftwarw will get stuck and never terminate.

while loop

Infinite Loop

Don't do it

package main

func main() {
   for { }
}

Switch

The switch statement is a multi-path conditional selection statement. This allow program to execute on different logical path depending on value of one variable. A switch statement use 2 multiple keywords to create a multi-case construct. The keywords are: {switch, case, default, fallthrough}

switch

Switch Diagram

Value based switch

The switch use a control variable that is local to the case statement. In next example we use "os" variable to analyze the operating system. Switch cases evaluate cases from top to bottom, stopping when a case succeeds.

//file switch_val.go
package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.", os)
	}
}

Note: When a case control variable has a particular case value switch breaks automatically and no other case is executed except when the case last statement is a fallthrough statement. The last is the "default" case is executed when variable has a different value from any other cases.

Conditional switch

Switch without a condition is the same as "switch true". This switch can be used to create a multi-deck conditional construct similar to multiple cascading if statements. This construct can be a clean way to write long if-then-else chains.

//file switch_con.go
package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
	}
}

Read next: Functions