Become a Golang Pro with These 10 “Defer” Tricks

DSL
3 min readDec 27, 2022

--

Go’s defer keyword is a powerful tool that allows you to specify a function call to be executed later, usually after the surrounding function has returned. Although it may seem like a simple concept, the defer keyword can be used in several advanced ways to improve the efficiency and reliability of your Go code.

Here in this post, we’ll explore ten advanced tricks for using delay in Go. From canceling events and releasing resources to printing the time used by a function and recovering from panics, these techniques will help you take your Go skills to the next level. Whether you’re a beginner who wants to learn more about defer, or an experienced developer looking to expand their knowledge, this post has something for you.

  1. Defer a function call to execute after the surrounding function returns:
func main() {
defer fmt.Println("This will be printed after main returns")
}

2. Defer a function call to execute in the reverse order they were deferred:

func main() {
defer fmt.Println("This will be printed last")
defer fmt.Println("This will be printed second")
defer fmt.Println("This will be printed first")
}

3. Defer a function call to execute even if a panic occurs:

func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()

// This will cause a panic
a := []int{1, 2, 3}
fmt.Println(a[3])
}

4. Defer a function call to close a file:

func main() {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()

// Do something with the file
}

5. Defer a function call to unlock a mutex:

func main() {
var mutex sync.Mutex
mutex.Lock()
defer mutex.Unlock()

// Do something that requires the mutex to be locked
}

6. Defer a function call to decrement a wait group:

func main() {
var wg sync.WaitGroup
wg.Add(1)
defer wg.Done()

// Do something that requires the wait group to be waited on
wg.Wait()
}

7. Defer a function call to roll back a transaction:

func main() {
tx, err := db.Begin()
if err != nil {
fmt.Println(err)
return
}
defer tx.Rollback()

// Do something with the transaction
err = tx.Commit()
if err != nil {
fmt.Println(err)
return
}
}

8. Defer a function call to release a resource:

func main() {
resource, err := AcquireResource()
if err != nil {
fmt.Println(err)
return
}
defer ReleaseResource(resource)

// Do something with the resource
}

9. Defer a function call to print the time taken by a function:

func main() {
start := time.Now()
defer fmt.Printf("Time taken: %v\n", time.Since(start))

// Do something that takes time
}

10. Deferring the execution of multiple functions:

defer fmt.Println("A")
defer fmt.Println("B")
defer fmt.Println("C")

In conclusion, the defer keyword in Go allows you to schedule a function call to be executed at a later point in time, after the surrounding function has returned. This can be useful for tasks such as cleaning up resources, releasing locks, rolling back transactions, and performing other types of deferred execution.

The defer statement can be used multiple times, and the deferred function calls will be executed in last-in-first-out order. This can be useful for stacking multiple deferred tasks, such as closing multiple files or releasing multiple locks.

Overall, the defer keyword is a powerful and convenient tool for ensuring that certain tasks are always performed in a Go program, regardless of the flow of the program.

--

--

DSL

Sr software engineer. Love in Go, JavaScript, Python, and serverless AWS. Follow me for tech insights and experiences. follow me on twitter @terraformia