The use of defer in Go
Marco Franssen /
7 min read • 1305 words
In my previous blog post I have covered how to setup your development environment for Golang including a simple hello world. In case this is your first Go project please have a look on this blog post first and then come back to learn about the use of defer
in Go.
Defer will always be triggered at the end of a function. So even if the code panics in some location of the executing code it will guarantee the deferred code will be executed. A panic in Go is an unhandled error and causes the program execution to get halted. After a panic a defer will be executed. Panic is not recommended to use it for exception handling. It is better to handle exceptions using Golang error
object. However for showcasing the use of defer I will use it in this blogpost, please don't take that as a best practice.
So lets take a look at an example:
Above code will result in the following output.
As you can see the deferred code will be executed at the end of the deferExample function just before the function returns. Now lets look at an example where the code panics. So lets add following functions to main.go and call it in your main function.
Above code is a recursive function which we will have panic as soon count is bigger then 3. fmt.Sprintf
is a way to format a string based on a value. See fmt documentation for more information on the verbs (%v
). This is required as the panic function paramter should be a string.
Another interesting topic is the recover()
function which allows you to recover from a panic down the call stack. As we are doing this recover in a self invoking anonymous deferred function call we are sure this will always be executed during a call to the deferPanicExample. So lets have a look at the new output of our program.
As you notice the Println
with message Return normally from recurse.
never happens as the function panics and therefore never reaches this line of code at the end of the function. Another thing to notice is that the defer in the recursive methods is only executed once the recursive call stack exits and will do that in reverse order of the call stack. Recursion basically works in a LIFO matter (Last in first out). Then the deferred anonymous function will trigger as the defer keyword guarantees to make this happen even if there is a panic. As we provided the count to panic you can see the log message contains the count at the moment the program panicked.
So now lets see how we can rewrite this function a bit to have it return normally without a panic to see how the flow will look like now.
Now you will notice the Println of Return normally from recurse.
does happen. You also notice the recover()
call results in nil as there was no panic, so nothing to recover from, and therefore not print the Recover from panic log
.
Practical usecase
Now we know about the internal workings of defer we can have a look at a more practical usecase.
So depending on your background you might know about the Closable interface in Java or the IDisposable interface in c#. In general those interfaces are implemented on classes like database connections, file readers etc. To free up memory after using those classes you generally call the close()
or dispose()
functions to free up those resources, so the garbage collector can free the memory. Not doing that is basically introducing memory leaks. In c# you do this using a try finally
block or the shorthand using
statement to guarantee this code is called no matter if an exception occurred or not.
In Go we just learned we can use defer
to make sure a piece of code is invoked with a 100% guarantee. So lets have a look on a small example reading X amount of bytes from a file.
This program will print the string from our text file up to the amount of 10 bytes. Again if you want to have more details on the verbs for string formatting have a look in the fmt package documentation.
As you can see I create a file in the same folder with the text I am super sexy.
. In general I don't want everyone to know I'm sexy ;-), so now you also know why I made the program only read the first 10 bytes. It would be anyhow enough to share with the world that I am super
.
So in general whenever any operation (Read, Peek etc.) on the file fails, in the end it will be guaranteed to that the file handle will be closed. Also note that multiple defer statements in the same function are executed in reverse order as you define them.
Thanks for reading this blog post. Also have a look at this blog on golang.org to get more details on defer panic and recover in Go.