If you have any questions or suggestions, please contact us in time. My official account is “Brain fried Fish”, GitHub address: github.com/eddycjy.

Hello, I’m fried fish.

A few days ago, I saw a friend in the reader exchange group asking for technical questions related to Go. The question was: “Everyone, WHEN I learned to defer, I was at a loss when I met the closure. Who knows better and can give me some advice?”

doubt

His question is the following question of the Go language defer. Let’s have a look:

func main() {
	var whatever [6]struct{}
	for i := range whatever {
		defer func() {
			fmt.Println(i)
		}()
	}
}
Copy the code

Please think about the answer to the output first.

According to his own understanding, this small partner thinks that xx should be output. But the final output results, may be a deviation from its thinking, temporarily unable to think.

To reassure

The output of this program is:

5, 5, 5, 5Copy the code

Why is it all 5, why is it not 0, 1, 2, 3, 4, 5?

The root cause is closures, for two reasons:

  • inforAfter the loop ends, local variablesiIs already 5, anddefer The closure of is a direct reference to the variable I.
  • In combination withdeferKeyword characteristics can be known in themainExecute after the method body ends.

Combined with the above, the final output is an increment of 5.

Think further

Now that we know why, let’s do another transformation. Let’s look at another case where the code looks like this:

func main() {
	var whatever [6]struct{}
	for i := range whatever {
		defer func(i int) {
			fmt.Println(i)
		}(i)
	}
}
Copy the code

Unlike the first case, this time we pass in the variable I. So what is his output?

The output of this program is:

5, 4, 3, 2, 1, 0Copy the code

Why 5, 4, 3, 2, 1, 0? Why not 0, 1, 2, 3, 4, 5? (Was the fried fish struck wrong?)

There are two fundamental reasons:

  • inforWhen looping, local variablesiAlready passed indefer func, belongs to value passing. Its value indeferThis is done when the statement is declared.
  • In combination withdeferKeyword characteristics are pressedAfter the advancedIn order of execution.

Combined with the above, the final output is 5, 4, 3, 2, 1, 0.

Next question

After a while, this friend had a new feeling. A new sample problem was thrown as follows:

func f1() (r int) { defer func() { r++ }() return 0 } func f2() (r int) { t := 5 defer func() { t = t + 5 }() return t }  func f3() (r int) { defer func(r int) { r = r + 5 }(r) return 1 }Copy the code

Main function:

func main() {
	println(f1())
	println(f2())
	println(f3())
}
Copy the code

Please think about the answer to the output first.

The output of this program is:

5 1Copy the code

Why one, five, one, instead of zero, ten, five, or whatever?

You are welcome to discuss and share your ideas in the comments section below.

My official account

Share Go language, micro service architecture and strange system design, welcome to pay attention to my public number and I exchange and communication.

The best relationship is mutual achievement. Your praise is the biggest motivation for the creation of fried fish. Thank you for your support.