#3 — Defer as a wrapper

Sometimes you need to defer with closures to be more practical or some other reasons I cannot guess right now. For example, to open a database connection, then run some queries and at the end to ensure that it gets disconnected.

Example

type database struct{} func (db *database) connect() (disconnect func()) {

fmt.Println("connect") return func() {

fmt.Println("disconnect")

}

}

Let’s run it

db := &database{}

defer db.connect()



fmt.Println("query db...")

Output

query db...

connect

Why it doesn’t work?

It doesn’t disconnect and it connects at the end, which is a bug. Only thing that happened here is that connect() gets saved aside until the func ends and it doesn’t run.

Solution

func() {

db := &database{} close := db.connect()

defer close()



fmt.Println("query db...")

}

Now, db.connect() returns a func and we can use it with defer to disconnect from the database when the surrounding func ends.

Output

connect

query db...

disconnect

Bad Practice:

Although it’s a bad practice to do this but I want to show you how you can do it without a variable. So, I hope you can see how defer and more generally how Go works.

func() {

db := &database{} defer db.connect()() ..

}

This code is technically almost the same as the above solution. Here, the first parenthesis is for connecting to the database (which happens immediately on defer db.connect() ) and then the second parenthesis is for defer to run the disconnector func (the returned closure) when the surrounding func ends.