英文:
How to understand `defer` in go language?
问题
在godoc(https://blog.golang.org/defer-panic-and-recover)中有一个例子:
- 延迟函数可以读取和赋值给返回函数的命名返回值。
在这个例子中,延迟函数在包围函数返回后递增返回值i。因此,该函数返回2:
func c() (i int) {
defer func() { i++ }()
return i
}
我也写了一个小程序:
package main
import "fmt"
func b() int {
i := 0
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
}
func main() {
fmt.Println("result =", b())
}
输出结果为:
4
5
6
7
result = 4
所以我很困惑,为什么第二个例子没有输出8
?
英文:
In the godoc(https://blog.golang.org/defer-panic-and-recover), there is an example:
> 3. Deferred functions may read and assign to the returning function's named return values.
>
> In this example, a deferred function increments the return value i
> after the surrounding function returns. Thus, this function returns 2:
func c() (i int) {
defer func() { i++ }()
return i
}
I also wrote a small progam:
package main
import "fmt"
func b() int {
i := 0
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
}
func main() {
fmt.Println("result = ", b())
}
the output is:
4
5
6
7
result = 4
So I am confused, why does the second example not output 8
?
答案1
得分: 10
请注意这部分内容:“可能会读取并分配给返回函数的命名返回值”。
这意味着:
func b() int {
var i int
defer func() { fmt.Println(i); i++ }()
return i
}
将输出0
和result = 0
,而:
func b() (i int) {
defer func() { fmt.Println(i); i++ }()
return i
}
将输出0
和result = 1
。
可以这样理解,我的第一个示例中的return i
将i
的值分配给一个隐藏的返回变量(因为它没有命名),然后继续执行defer
语句(只修改局部变量i
),而在第二个示例中,我们直接将值分配给返回变量(因为它有命名),所以defer
语句可以修改它。
基本上,你的程序可以这样解释:
package main
import "fmt"
func b() (hiddenVariable int) {
i := 0
for ; i < 4; i++ {
defer func() { fmt.Println(i); i++ }()
}
hiddenVariable = i; return // 隐含的 return i 的意思
}
func main() {
fmt.Println("result =", b())
}
英文:
Note the part that says "may read and assign to the returning function's named return values."
This means that:
func b() int {
var i int
defer func() { fmt.Println(i); i++ }()
return i
}
will say 0
and result = 0
, while:
func b() (i int) {
defer func() { fmt.Println(i); i++ }()
return i
}
will say 0
and result = 1
.
It might help to imagine that the return i
in my first example assigns the i
value to a hidden return variable (because it's not named), then goes on to execute the defer
statements (which only modify the local variable i
), while in the second example we assign directly to the return variable (because it's named) and so the defer
statement is able to change it.
Basically your program could be interpreted like this:
package main
import "fmt"
func b() (hiddenVariable int) {
i := 0
for ; i < 4; i++ {
defer func() { fmt.Println(i); i++ }()
}
hiddenVariable = i; return // implicit meaning of return i
}
func main() {
fmt.Println("result = ", b())
}
答案2
得分: 0
根据我对defer的了解以及查看你的代码,我想说for循环推迟了后续的'i'的打印输出,但是for循环仍然运行,因此影响了由func b()返回的'i',它的值是4。
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
由于打印语句及其对'i'的值的推迟,它们会递增超过4,但是for循环后面的'i'仍然保持为4。
英文:
Based solely on what I learned about defer and after looking at your code, I'd like to say that the for loop defers the print out of subsequent 'i's until later, however, the for loop still runs and therefore affects the 'i' returned by
func b(), which is 4.
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
Because the print statement and it's 'value' for 'i' is deferred, they increment beyond 4, but the 'i' after the for loop remains at 4.
答案3
得分: 0
defer
语句将一个函数调用推入一个列表中。保存的函数调用列表会在包围函数返回后执行。你的**func b()**在语义上等同于:
func b() int {
i := 0
for ; i < 4; i++ {
}
ret := i
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
return ret
}
因此,b()返回4。
英文:
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.
Your func b() is semantically equivalent to:
func b() int {
i := 0
for ; i < 4; i++ {
}
ret := i
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
return ret
}
Ergo b() returns 4.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论