Go Defer Simplified with Practical Visuals
Learn about Golang’s defer statement with various usage examples.




👉 Go doesn’t need destructors because it has no built-in constructors. This is a good balance.
👉 Defer resembles to “finally” however the defer belongs to the surrounding “func” while the finally belongs to an exception “block”.

👊 Bonus: See my comment here about the internals of defer if you’re curious about how it works. It’s actually been documented pragmatically as “it runs — after — the surrounding func returns”, however, there are some other inner details.

Releasing acquired resources
Defer funcs are often used to release the acquired resources inside a func.


Save us from panic
Defer can recover from a panic to prevent the termination of a program if the panic emitted from the same goroutine.


Deferred closure
A deferred func can be of any type of func. So, when used with an anonymous func — obviously — the func becomes aware of its surroundings.
Notice that it sees the latest state of the surrounding values, check out:


Params evaluation
Go runtime will save any passed params to the deferred func at the time of registering the defer— not when it runs.

Example
Declare a dummy func that registers a deferred closure. It also uses a named result value “n” to increase the passed number for the second time:
func count(i int) (n int) { defer func(i int) {
n = n + i
}(i) i = i * 2
n = i return
}
Let’s try:
count(10)// output: 30
What happened?



In some situations defer can help you to change the result value before the return by using the named result values as seen in the example.

Multiple defers
Multiple defers are saved in a stack list. So, the last registered defer will run as the first. Beware: Using multiple defers may hinder the readability.
Example


Deferred methods
You can also use methods with defer. However, there’s a quirk. Watch.
Without pointers
type Car struct {
model string
}func (c Car) PrintModel() {
fmt.Println(c.model)
}func main() {
c := Car{model: "DeLorean DMC-12"} defer c.PrintModel() c.model = "Chevrolet Impala"
}
Output
DeLorean DMC-12
With Pointers
func (c *Car) PrintModel() {
fmt.Println(c.model)
}
Output
Chevrolet Impala
What’s going on?

Remember that the passed params to a deferred func are saved aside immediately without waiting for the deferred func to be run.
So, when a method with a value-receiver is used with defer, the receiver will be copied (in this case Car) at the time of registering and the changes to it wouldn’t be visible (Car.model). Because the receiver is also an input param and evaluated immediately to “DeLorean DMC-12” when it’s registered with the defer.
On the other hand, when the receiver is a pointer when it’s called with defer, a new pointer is created but the address it points to would be the same with the “c” pointer above. So, any changes to it would be reflected flawlessly.


Alright, that’s all for now. Thank you for reading so far.
Let’s stay in touch:
- 📩 Join my newsletter
- 🐦 Follow me on twitter
- 📦 Get my Go repository for free tutorials, examples, and exercises
- 📺 Learn Go with my Go Bootcamp Course
- ❤️ Do you want to help? Please clap and share the article. Let other people also learn from this article.