Today we are going to learn about defer keyword in Golang. What Defer does and how it works we are going to see that via implementation of some code which is focused on defer keyword of Golang. So before starting let’s understand the defer via it’s definition then we are going to implement some code on it.
What is Defer?
Defer statement is used to execute a function call just before the surrounding function where the defer statement is present returns.The definition might seem complex but it’s pretty simple to understand by means of an example.
We have finished the definition reading part and via it we understand that a defer runs before exiting or returning from a function, means the last second last step of function which have defer keyword used.
Now let’s write some code to understand it in via code.
EXAMPLE 1
package main
import (
"fmt"
)
func sliceToName(s []string) {
var str string
fmt.Println("Started joining slice into string")
for _, is := range s {
str += is
}
fmt.Println("Create name from slice is", str)
}
func main() {
defer fmt.Println("Finished joining slice into string")
s := []string{"G", "O", "L", "A", "N", "G"}
sliceToName(s)
}
The above code is a simple program to combine the slice of string into a single string to make it a full name.I know I can use the join function as well from the string package but for testing we decided to make our own.The sliceToName function takes a string slice as a function parameter and prints the combined values of a slice into string. The most important line is defer which we have in our main function as you can see we have used fmt.Println as before that we have added defer keyword in it so now let’s run the code and the sequence of the code execution.
OUTPUT:
Started joining slice into string
Create name from slice is GOLANG
Finished joining slice into string
The sliceToName function starts executing and prints the first two lines of the above output and before it could return our defer function which is in main function executes and prints the text Finished joining slice into string.
Now let’s try to move this defer from main function to a seperate function and call that function from sliceToName and then let’s see what will be the output of that code will be.
EXAMPLE 2
package main
import (
"fmt"
)
func DeferedFinished() {
fmt.Println("Finished joining slice into string")
}
func sliceToName(s []string) {
defer DeferedFinished()
var str string
fmt.Println("Started joining slice into string")
for _, is := range s {
str += is
}
fmt.Println("Create name from slice is", str)
}
func main() {
s := []string{"G", "O", "L", "A", "N", "G"}
sliceToName(s)
}
So you can see we have seperated our print statement from main function to a seperate function and all of the logic is same except the DeferedFinished function we have created it and calling it in our sliceToName function with the defer keyword now let’s check the output.
OUTPUT:
Started joining slice into string
Create name from slice is GOLANG
Finished joining slice into string
The above output is also same as we have for the first example so now you understand how defer works now.
Multiple Defer Keywords Case
Now Let’s try to use multiple defer keywords with multiple print statement and then check the order of the execution of the code how they works.
Let’s check the code first without using the defer keyword.
EXAMPLE 1
package main
import (
"fmt"
)
func deferSequence(i int) {
fmt.Println("Defer Sequence Number", i)
}
func main() {
deferSequence(5)
deferSequence(4)
deferSequence(3)
deferSequence(2)
deferSequence(1)
}
As you can see we have called deferSequence function five times and have given numbers as well to check the output in which sequence are they running. Now let’s check the output first.
OUTPUT:
Defer Sequence Number 5
Defer Sequence Number 4
Defer Sequence Number 3
Defer Sequence Number 2
Defer Sequence Number 1
The above output result is in sequence without using defer keyword.
Now check the another approach which have defer keyword included in all functions which is called from main.
EXAMPLE 2
package main
import (
"fmt"
)
func deferSequence(i int) {
fmt.Println("Defer Sequence Number", i)
}
func main() {
defer deferSequence(5)
defer deferSequence(4)
defer deferSequence(3)
defer deferSequence(2)
defer deferSequence(1)
}
So in above code we have added defer keyword for each function now let’s check the output.
OUTPUT:
Defer Sequence Number 1
Defer Sequence Number 2
Defer Sequence Number 3
Defer Sequence Number 4
Defer Sequence Number 5
So as you can see the order of the execution of each function now have reversed or as we can say it follows Last In First Out – LIFO order.
Defer to close files as well
we also uses defer keyword to close the open files as well. You can see the code which is written below
EXAMPLE
package main
import (
"fmt"
"os"
)
func isError(err error) bool {
if err != nil {
fmt.Println(err.Error())
}
return (err != nil)
}
func main() {
var path = "app.txt"
fmt.Println("Opening a file ")
var file, err = os.OpenFile(path, os.O_RDWR, 0644)
if isError(err) {
return
}
defer file.Close()
}
Using Defer in Loop
So we are also trying to use defer is loop as well via this approach we are going to reverse a string.
EXAMPLE
package main
import (
"fmt"
)
func main() {
name := "Kuldeep"
fmt.Printf("Original String: %s\n", name)
fmt.Printf("Reversed String: ")
for _, v := range []rune(name) {
defer fmt.Printf("%c", v)
}
}
In the above code we have a name variable and then we are running a loop on it before running loop we are converting it to rune so we can run loop on each characters which is rune type now and the with the help of formatter we are printing getting the characters of that run and also we have added defer keyword as well in that print statement.
OUTPUT:
Original String: Kuldeep
Reversed String: peedluK
So we can see the above output which is reversed with the help of the defer keyword.
Thanks for reading the article…