The defer keyword in Go is used to…literally…defer something to the end of a function block.

It’s saying “do stuff, then do this at the very end right before this function is finished”.

Example:

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	counts := make(map[string]int) // map to put in counts
	files := os.Args[1:]           // filenames
	for _, arg := range files {
		f, err := os.Open(arg)
		defer closeFile(f) // this happens later
		if err != nil {
			fmt.Fprintf(os.Stderr, "err: %v\n", err)
			continue
		}
		input := bufio.NewScanner(f)
		for input.Scan() {
			counts[input.Text()]++
		}
	}
	for line, n := range counts {
		fmt.Printf("%d\t%s\n", n, line)
	}
}

func closeFile(f *os.File) {
	fmt.Println("closing")
	err := f.Close()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

// go run main.go input.txt input.txt
// 3       sup bro
// 3       bitch
// 4       yoyo
// 8       hey
// 32      yo
// 1       heyeyeye
// closing
// closing

The line defer closeFile(f) here is saying “after all this following stuff is done, close the file”. It’s important to close the file after reading it, so we can see that defer keyword helps us follow good practices for cleanup stuff.

Note: This happens at the end of the enclosing function, not the enclosing block. So in the above example, we see “closing” run twice at the end before the loop exits, not the end of the loop iteration.

Other things to note here: There is no while keyword in go, see the line for input.Scan() — this functions as a while loop.

defer as a hook

The term “hook” here is my invention. However, defer can be used as a hook for entry/exit of a function. It can be used for cleanup, or for catching errors. The pattern here for doing this is often using:

  • named parameters (error, etc.)
  • function literals, like an iife in JS

func handleWork() result string, err error {
	defer func() {
		if p := recover(); p != nil {
			fmt.Errorf("work panic: %s", err)
		} else {
			fmt.Printf("work was successful: %s", result)
		}
	}()
	/* 
		do some heavy work
	*/
	return result, err
}


end of storey Last modified: