A quick look at golang’s defer

What is defer

defer is a keyword of the Go Programming Language indicating that the following function is to be called at the end of the current function. It denotes of a deferred action.

It’s particularly useful to close indicate early that a file descriptor or a network connection must and will be closed at the end of the current function.

Simple use of defer

For the simple case of closing a network connection handle, defer can be used as follows:

func onConn(conn net.Conn) {
    defer conn.Close()
}

This guarantees us that the connection will be closed at the end of our connection handling function.

Multiple uses of defer

defer can be called multiple times to stack up multiple actions that must be done on the completion of the current function:

func onConn(conn net.Conn) {
    defer log.Println("Connection closed.")
    defer conn.Close()
}

The documentation alludes to the fact that these function are pushed on a list (in practice, most probably a LIFO Stack) that is executed when exiting the function.

Execution order

While multiple calls to defer can be made, the order in which the deferred actions will be executed is dependant of the declaration order:

func onConn(conn net.Conn) {
    defer log.Println("After connection close. ")
    defer log.Println("Connection closed.")
    defer log.Println("Before connection close.")
    defer conn.Close()
}

Will give the following output:

2016/08/27 14:43:52 After connection close.
2016/08/27 14:43:52 Connection closed.
2016/08/27 14:43:52 Before connection close.

Conditionally adding defer calls

Conditional calls to defer can be added in your code, however the declaration and execution order mentioned before will apply in the same capacity:

func onConn(conn net.Conn) {
    defer log.Println("After connection close. ")
    defer log.Println("Connection closed.")
    defer log.Println("Before connection close.")
    if true {
        defer log.Println("We did something!")
    }
    defer conn.Close()
}

Will give the following output:

2016/08/27 14:51:23 We did something!
2016/08/27 14:43:52 After connection close.
2016/08/27 14:43:52 Connection closed.
2016/08/27 14:43:52 Before connection close.

Grouping defer actions

In the case a lot of deferred actions must be declared, it could be cool to group them. Ideally I would have liked to have a syntax like this to do it:

defer {
    // All my defered actions
}

But alas this doesn’t exist. We can however create and execute an anonymous closure right there instead:

func onConn(conn net.Conn) {
    defer func() {
        // All my defered actions
    }()
}

Note the () at the end of the block indicating we execute our anonymous closure immediately.

This allows for an elegant logical group of deferred actions to be created.



Enter your desired user name/password and after your comment has been reviewed by an admin it will be posted and your account will be enabled. If you are already registered please login before posting.