Golang Control Flow

As we have covered Golang ‘language fundamentals’ in our Third Chapter,  let’s explore ‘Control Flow’ and ‘Functions’ in this chapter.
The golang control flow statements are used to break the flow of execution by branching,looping, decision making statements by enabling program to execute code based on the conditions. All programmers must know the control flows like if-else, switch case, for loop,break,continue,return.
  • if/else
  • if/else if/else
  • if/else if/else if/…../else
The if statement is similar to other programming languages. If statement is expecting some condition and based on the condition it will execute the code.
if condition { 
//Executable code
}
if condition {
//Executable code
}else 
{
//Executable code
}
if condition
//Executable code
}else if condition{ 
//Executable code
} else{
//Executable code 
}
Note:  use else/else if just after closing of if statement’s closing bracket “}“ otherwise you will get compile time error.
main.go
package main
import (
 "fmt"
)
func main() {
 no := 56
 if true {
 fmt.Println("This will work")
 }
 if false {
 fmt.Println("This will not work")
 }
 if !true {
 fmt.Println("This will not work")
 }
 if !false {
 fmt.Println("This will work")
 }
 n := 45
 if n%2 == 0 {
 fmt.Println("even")
 } else { //use else just after “}” end of if
 fmt.Println("odd")
 }
 //If with short statement
 if computer := "Dell"; no > 50 {
 fmt.Println(computer)
 }
}
Demo Screenshot –

For loop

Golang has only one loop which for loop. Like other programming languages it doesn’t have while and do while loop. But we can use for loop as while loop.
for initialization;condition;increment/decrement{
 //Executable code
 }
package main

import (
 "fmt"
)
func main() {
 //Nested for loop
 for i := 1; i <= 5; i++ {
 for j := 1; j <= 10; j++ {
 fmt.Print("\t")
 fmt.Println(j * i)
 }
 }
 //for as a while loop
 k := 0
 for k < 10 {
 fmt.Println(k)
 if k >= 10 {
 break //break statement is used to break the control if cond occurs
 }
 k++
 }
 //for with no condition
 m := 0
 for {
 fmt.Println(m)
 if m >= 10 {
 break
 }
 m++
 }
 for i := 65; i <= 122; i++ {
 fmt.Printf("%v - %v - %v \n", i, string(i), []byte(string(i)))
 //converted int type to string and []byte
 }
}

Switch case

Most programming languages have switch case to avoid complex if-else if statements.
  • we can compare only values of same types
  • we can set optional default statement if condition fails
  • we can use expression if need to compare condition based on value to use
switch value/cond {
 case ‘value/cond’: executable code
 case ‘value/cond’: executable code
 …..
 default : default statements if all above fails.
 }
“fallthrough” is optional in switch case. This keyword is used in case statement and when it is encountered, it will go to next case even if next case is failing condition. So it is optional in this switch case.
We can specify multiple values in case statement. Also we can return a value based on switch cases.
main.go
package main
import (
 "fmt"
)
func main() {
 test("one")
}
func test(str string) {
 val := str
 switch val {
 case "zero",”Zero”:
 fmt.Println("Zero:", val)
 fallthrough /*even if next condition fails
 it will enter into next case */
 case "one",”One”:
 fmt.Println("One:", val)
 break
 default:
 fmt.Println("Wrong one !!")
 }
}
Normally we switch on value of a variable but Golang allows you to switch on type also.
main.go
package main
import (
 "fmt"
)
type wish struct {
 message string
 name string
}
func Type(x interface{}) {
 switch x.(type) { //this one is assert
 case int:
 fmt.Println("int")
 case string:
 fmt.Println("string")
 case wish:
 fmt.Println("wish")
 default:
 fmt.Println("Unknown Type")
 }
}
func main() {
 Type(7)
 Type(wish{"Good Morning", "User"})
}

Functions

Functions are no. of statement that together perform a task and make execution flow more reliable so that we can reuse the code whenever needed.
The execution of Go program starts from the main function itself func main(){    } . A function takes one or more parameters and return one or more outputs. Like other programming languages, go explicitly needs to return values.
The Syntax is
func <function name>(parameters)(return types){
 …………….//Executable code
 return <value> //If function is returning
}
Function starts with keyword func and its name. The parameters need to define like var_name  var_typeAfter this we need to write return type if function is going to return. Writing of function can be difficult so better idea is to break into manageable code,rather that going for full implementation.
func square(n int)(int){
 return n*n
 }
The return statement is used to immediately stop and return value to its caller. Go has a capability to return multiple values.
x,y:=func(5)
 func(n int)(int,int)
 {
a:=8
return a,n
}
Mostly we are returning result along with error like x,err:=func(). Avoid using nameless return.

Variadic Function

This one is special form of function which can take any arguments. It is like varargs in Java. We can pass any number of parameters to the variadic function of same type. To make function variadic you just need to put three dots … before the arguments type. It will allow you to pass any number of arguments to the function.
func sum(args ..int)int{ //Variadic function
 total:=0
 for value:=range args{
 total+=value
 }
 return sum
 }
 func main(){
 fmt.Println(sum(54,76,43,23,78)) //Passing multiple values
 data:=[]int{33,87,43,21} //Passing Slice of ints
 fmt.Println(sum(data...))
Here ,you can see how the fmt.Println() is implemented in “fmt” package. func Println(a …interface{})(n int,err error)
So the Println function can take any number of arguments of any type. We can also pass slice of ints for the variadic function.
func main(){
 xs:=[]int{43,67,43,21}
 fmt.Println(sum(xs…))
}

Function as expression

We can pass function to an expression and call that function by using expression/variable name. This is the only way to have one function inside another.
If you see the type of expression then it will be a func()
func main(){
message:=func(){
fmt.Println(“Good Morning User”)
}
message() //calling function by expression name/var name as anonymous fun
fmt.Printf(“%T”,message) //Its type will be a func()
No identifier is there and function is anonymous(nameless)

Closure

We can create function inside functions i.e. nesting of functions.
For this purpose, Go supports anonymous function i.e. function without name which will become local to the function.
func main(){
 sum:=func (x,y int)(int){
 return x+y
 }
 fmt.Println(“Sum is”,sum())
}
Closure helps us limit the scope of variables used by multiple functions.Without closure,for two or more funcs to have access to same variable, that variable would need to be in package scope.
Callbacks
Passing a function as an argument is called callback in golang. Here, we can pass function as an argument.
func main(){
 show([ ]int{43, 76, 34}, func(n int) {
 fmt.Println(n)
 })
}

 func show(numbers [ ]int, call func(int)) {
 for _, n := range numbers {
 call(n)
 }
}
Here we are passing func call( ) as an argument to the func show( )

Recursion

Recursion is a function which calls itself. It is like two mirrors facing to each other.
func factorial(n int) int {
 if n==1{
 fmt.Println(n)
 }
 return n*factorial(n-1) //factorial() will call itself till it reaches to 0
  • Recursion will create a stack of function calls every time.
  • Sometimes recursion is the best solutions.
  • Closure and Recursion are the powerful technique of programming which forms functional programming and most of people find recursion difficult to understand than the control flow statements.

Defer

Go has a special statement defer which schedules a function call to execute before function completes.
Defer is used when resources need to be freed away i.e. same like finally block in java which is used to put the resource releasing logic.
For ex. Whenever we open file we need to make sure to close it or while connecting to database after completion of task we need to close the connection.
f,_:=os.Open(“filename.txt”)
defer f.Close()

Advantages→

  • It keeps our Close() near to the Open() and it’s easy to understand
  • deferred func will always run even if runtime panic err occurs
main.go
package main
import (
 "fmt"
 "os"
)

func addition(number1 int, number2 int) int {
 return number1 + number2 //returning one value
}

func pass(value1 int, value2 int) (int, int) {
 return value1, value2
} //returning multiple values

//Variadic Function
func sum(numbers ...float64) (res float64) {
 for _, number := range numbers {
 res += number
 }
 return sum
}

//Func as expression value --> Closure
func decrement() func() int {
 x := 50
 return func() int {
 x--
 return x
 }
}

//Callbacks
func show(numbers []int, call func(int)) {
 for _, n := range numbers {
 call(n)
 }
}

//Recursion
func factorial(n int) int {
 if n == 0 {
 return 1
 }
 return n * factorial(n-1)
}

func main() {
 add := addition(1087, 3422)
 fmt.Println("Addition:", add)
 get, set := pass(123, 543)
 fmt.Println("Return Multiple Values:", get, set)
 data := []float64{3.3, 4.4, 5.5}
 fmt.Println(sum(1.1, 2.2, 3.3))
 fmt.Println(sum(data...))

 //Function as expression
 message := func() {
 fmt.Println("Good Morning User")
 }
 message() //Expression name as function call
 fmt.Printf("Type of Expression Fun:%T\n ", message)

 //Closure
 sum := func(x, y int) int {
 return x + y
 }
 fmt.Println("Sum is:", sum(435, 765))
 dec := decrement()
 fmt.Println("Decremented Value:", dec())

 show([]int{43, 76, 34}, func(n int) {
 fmt.Println(n)
 })

 //Recursion
 fmt.Println("Factorial of 7 using Recursion", factorial(7))

 //Defer
 f, _ := os.Open("log.txt")
 fmt.Println("Opening file.....")
 defer f.Close()
 fmt.Println("File closed")
}

Pass By value

Strictly speaking, there is only one way to pass parameters in Go is Pass By Value. Whenever a variable is passed as a parameter, a copy of that variable is created and passed to the function and this copy will be at a different memory location.
In case, variable is passed as a pointer argument then again new copy of parameter is created and that will point to the same address.
main.go
 package main
import (
 "fmt"
)
type person struct {
 name string
 age int
}
//Pass by value 
func changeIt(ch person) {
 ch.name = "Rafel"
}
//Pass by value using pointer
func change(ch *person) {
 ch.name = "Rafel"
}
func main() {
 per := person{"Roger", 64}
 changeIt(per)
 fmt.Println(per) //]Here still we are getting old values
 change(&per)
 fmt.Println(per) //Here value is changing
}
Note that even though func changeIt() changes the name to ‘Rafel’, it does not affect the variable name in main function. This happens because function modifies copy of variable not the original one.
But the func change() is modifying the value because &per and per are two different pointers pointing to same struct which is stored at the same memory address.

Anonymous Function

Anonymous functions are the self-executing functions which are nameless i.e.they do not have name. Only through anonymous function we can do nesting of functions i.e. one function inside another.
func main(){
 func( ){
 fmt.Println(“Hello World...I am Anonymous Function”)
 } ( )
Well, we are now all set with major control flows and functions for Golang. In our next chapter, we will explore Golang Data Structures. Make sure you check it out! 

subscribe to our newsletter

   
   
Related Posts

Leave a Comment

goland-data-structuresgolang-error-handling