Welcome To Golang By Example

Defer and Methods in Go (Golang)

Table of Contents

Overview

defer statement is also applicable  for methods in a similar way it is applicable to functions. Let’s see an example

Example

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    err := writeToTempFile("Some text")
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Printf("Write to file succesful")
}

func writeToTempFile(text string) error {
    file, err := os.Open("temp.txt")
    if err != nil {
        return err
    }
    defer file.Close()

    n, err := file.WriteString("Some text")
    if err != nil {
        return err
    }
    fmt.Printf("Number of bytes written: %d", n)
    return nil
}

In the above program, we do defer file.Close() after opening the file. Close is the method which is defined on the file instance. This will make sure that closing of the file is executed even if the write to the file results into an error. Defer function makes sure that the file will be closed regardless of number of return statements in the function.

Let’s see another example of a method called on a custom struct in a defer function

package main

import (
	"errors"
	"fmt"
)

type employee struct {
	name string
}

func (e *employee) setName(name string) error {
	defer e.setDefaultName()
	if len(name) < 3 {
		fmt.Println("Length of name passed is less than 3")
		return errors.New("Length of name cannnot be less than 3")
	}
	e.name = name
	return nil
}

func (e *employee) setDefaultName() {
        fmt.Println("In the setDefaultName function")
	if e.name == "" {
		e.name = "DefaultName"
		fmt.Println("Default name is set")
	}
}

func main() {
	e1 := &employee{}
	e1.setName("John")
	fmt.Printf("First employee name is: %s\n", e1.name)

	fmt.Println()
	e2 := &employee{}
	e2.setName("Ko")
	fmt.Printf("Second employee name is: %s\n", e2.name)
	return
}

Output

In the setDefaultName function
First employee name is: John

Length of name passed is less than 3
In the setDefaultName function
Default name is set
Second employee name is: DefaultName

In the above program we have a custom struct employee

type employee struct {
	name string
}

struct employee has a setName function which sets the name. But this function also raises an error is length of name passed is less than 3.  We have a defer function in the setName which executes after setName finishes and checks weather the name is empty. If it is empty then it sets a default name. This defer function is actually a method setDefaultName

func (e *employee) setDefaultName() {
	if e.name == "" {
		e.name = "DefaultName"
		fmt.Println("Default name is set")
	}
}

Then we create an instance of employee e1 and sets its name

Since length of "John" is greater than 3, the setName function doesn't raises an error. But if you will notice the output,  the defer function setDefaultName is still executed

In the setDefaultName function
First employee name is: John

Then we create an instance of employee e2 and sets its name

e1 := &employee{}
e1.setName("Ko")

Since length of "Ko" is less than 3, the setName function raises  an error. defer function setDefaultName also gets executed in this case and it sets the default name. That is why you see below output in this case

Length of name passed is less than 3
In the setDefaultName function
Default name is set
Second employee name is: DefaultNam