Understand how Go's defer works

I was thinking about defer for the processing that I wanted to execute at the end of the function, but I tried to dig deeper into defer to understand it properly.

A rough explanation of defer

--If you describe the process with defer, it will be executed at the end of func. --In the example below, "Today" is executed and the end of func is reached, so "Friday." Is executed after that.

func hogehoge() {
    defer fmt.Println("It's Friday.")
    fmt.Println("today....")
}
today....
It's Friday.

A little deep digging

According to the explanation of Tour of Go

  1. Execution is postponed until the enclosed function is returned.
  2. The argument of the defer call is evaluated immediately, but is postponed until the execution is returned.

There is an explanation. I can understand 1 somehow, but I was curious about the description of 2 ** "immediately evaluated" **, so I would like to explain it in detail later.

Also, according to the explanation of Programming Language Go

  1. By using defer, you can clearly describe the release of resources.
  2. The correct position of defer is immediately after successful acquisition of resources

There is an explanation to that effect. The following is an example.

resp, err := http.Get(url)
defer resp.Body.Close() //Actually, error judgment should be put before defer

In Java, close () is often written at the end of the function, and sometimes I forget to write close (), but If it is go, it is recommended to put the release process immediately after acquiring the resource using defer.

What does it mean to be evaluated immediately?

I think it's faster to actually look at the code, so take a look at the sample below.

func main() {
    defer today()()
    fmt.Println("today....")
}

func today() func() {
    fmt.Println("Is it Friday?")
    return func() {fmt.Println("Or is it Saturday?")}
}

What if you do this? Since defer is called at the end of main, `today ...` is called first, then ``` Friday in today ()? `, Finally` or Saturday? You might wonder if it's going to be `` `.

But when I try it

Is it Friday?
today....
Or is it Saturday?

It becomes. Why? The point is that the return value of today () is functional.

The argument of the ** defer call in the previous section is evaluated immediately, but please pay attention to the part **.

defer today()()The evaluation is carried out in the description part of.(Why are there two parentheses? You may think for a moment, but I would like to explain at the end because the story is off.)

So

fmt.Println("Is it Friday?")

Is executed. After that, proceed to the processing in main

fmt.Println("today....")

Is executed.

Then with delayed execution

fmt.Println("Or is it Saturday?")

It is a flow.

Why are there two parentheses for defer today () ()? ??

Doesn't it have 2 parentheses? ?? You might think, but this is necessary. What happens if you try using one parenthesis?

func main() {
    defer today()
    fmt.Println("today....")
}

func today() func() {
    fmt.Println("Is it Friday?")
    return func() {fmt.Println("Or is it Saturday?")}
}
 today....
 Is it Friday?

The order has changed and Saturday is gone. .. .. ..

defer today() //1
defer today()() //2

The two descriptions are fundamentally different.

1 is just the process of defer and executes the today function. That is, today at the end of the main function()Is executed. In this process, the anonymous function is returned, but the anonymous function is not executed.

On the other hand, 2 is today()The function returned in is executed at the end of the main function. To make it easy to understand, 2 is an anonymous function in the processing of defer.func() {fmt.Println("Or is it Saturday?")}Is running.

Recommended Posts

Understand how Go's defer works
Understand how Zabbix API works
How Python module import works
Understanding how it works Twilio # 1-Introduction