This article is written by the golang tutorial column to introduce you to the interview questions about the Go for loop. I don’t know how much you know about the for loop. Do you think it’s a trap? Below I will talk about for-related issues in detail. I hope it will be helpful to friends who need it!
I don’t know how many Go interview questions and leaks are related to for loops. Today I took a closer look over the weekend and discovered redefining for loop variable semantics.
Well-known hardcore tycoon Russ Cox said that he has been studying this issue and said that ten years of experience shows that the cost of current semantics is very high.
Question
Case 1: Get the address character
In the Go language, we write When using a for statement, sometimes the running and guessed results are inconsistent. For example, the code of the first case below:
var all []*Itemfor _, item := range items { all = append(all, &item) }
Is there something wrong with this code? What is stored in the item variable in the variable all? Is it the item value of each loop?
In fact, during the for loop, the same item is stored in the variable all each time, which is the item value of the last loop.
This is a question that often appears in Go interviews. It is more interesting when combined with goroutine. After all, there are still problems such as out-of-order output.
If you want to solve this problem, you need to rewrite the program as follows:
var all []*Itemfor _, item := range items { item := item all = append(all, &item) }
To re-declare an item variable, store the item variable of the for loop and then append it.
Case 2: Closure function
The following is the code of the second case:
var prints []func()for _, v := range []int{1, 2, 3} { prints = append(prints, func() { fmt.Println(v) }) }for _, print := range prints { print() }
This program What is the output of ? Without the & address character, does it output 1, 2, 3?
The output result is 3, 3, 3. Why is this?
One of the key points of the problem is the closure function. In fact, all closures print the same v. The output is 3 because after the for loop ends, the final value of v is set to 3, and that's it.
If you want to achieve the desired effect, you still need to use universal reassignment. The rewritten code is as follows:
for _, v := range []int{1, 2, 3} { v := v prints = append(prints, func() { fmt.Println(v) }) }
Add the v := v
statement, and the program output results are 1, 2, 3.
Carefully look through the Go projects you have written. Are they all familiar to you? With this transformation method, we won.
Especially with the Goroutine writing method, many students will be more likely to overturn here.
Solution
Fix ideas
In fact, the Go core team has internally and in the community After discussing for a long time, I hope to redefine the syntax of for loop. The goal to be achieved is: Make the loop variable each iteration instead of each time it is looped.
The solution is: add an implicit reassignment at the beginning of each loop body of each iteration variable x, that is, x := x
, This will solve the pitfalls hidden in the above program. It's the same as what we do now, except that we add it manually. What the Go team does is to handle it implicitly in the compiler.
Let users decide for themselves
What is more embarrassing is that the Go team prohibits redefining the language in Proposal: Go 2 transition, so rsc cannot be directly Do this.
It will therefore be up to the user to control this "destruction" by changing the semantics based on the go line in each package's go.mod file.
If we change the for loop discussed in this article to iteration in Go1.30, then the go version declaration in the go.mod file will be a key.
As shown below:
Go 1.30 or later will iterate over the variable each time, while earlier Go versions will iterate over the variable each time.
In this way, the for loop problems mentioned above will be solved within a certain range.
Summary
The variable problem during for loop has always been a favorite topic of major Go examiners. In addition, it is true that this problem will be encountered when actually programming Go code. Kind of pit.
Although rsc hopes to pioneer the go.mod file and use the go version declaration to modify the semantics (addition and deletion are not allowed). This undoubtedly opens a backdoor to Go1 compatibility guarantee.
If implemented, this change will result in different semantics between the previous and later versions of Go. Might as well become a semantic switch in a go.mod file.
This is obviously a very difficult question.
The above is the detailed content of How pitiful is the for loop in Go language?. For more information, please follow other related articles on the PHP Chinese website!