-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
120 additions
and
631 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# 7.15 defer 的变量快照什么情况会失效? | ||
|
||
关于 defer 的基本知识点,我在以前的教程中有写过:[流程控制:defer 延迟语句](https://golang.iswbm.com/c01/c01_12.html) | ||
|
||
其中有一个知识是 defer 的变量快照,举个简单的例子来说 | ||
|
||
在下面这段代码中,会先打印出来 `18`,即使后面 age 已经被改变了,可 defer 中的 age还是 修改之前的 `0`,这种现象称之为变量快照。 | ||
|
||
```go | ||
func func1() { | ||
age := 0 | ||
defer fmt.Println(age) // output: 0 | ||
|
||
age = 18 | ||
fmt.Println(age) // output: 18 | ||
} | ||
|
||
|
||
func main() { | ||
func1() | ||
} | ||
``` | ||
|
||
对于这个输出结果,相信还是挺容易理解的。 | ||
|
||
接下来,我请大家再看下面这个例子,可以猜猜看会输出什么? | ||
|
||
```go | ||
func func1() { | ||
age := 0 | ||
defer func() { | ||
fmt.Println(age) | ||
}() | ||
age = 18 | ||
return | ||
} | ||
|
||
func main() { | ||
func1() | ||
} | ||
``` | ||
|
||
正确的答案是:`18`, 而不是 `0` | ||
|
||
你肯定会纳闷:不对啊,defer 不是会对变量的值做一个快照吗?答案应该是 0 啊,为什么会是 18? | ||
|
||
实际上,仔细观察,可以发现上面的两个例子的区别就在于,一个 defer 后接的是单个表达式,另一个 defer 后接的是一个函数,并且不是普通函数,而是一个匿名的闭包函数。 | ||
|
||
根据闭包的特性,实际上在闭包函数存的是 age 这个变量的指针(原因可以查看上一篇文章:[Go 语言面试题 100 讲之 014篇:说说 Go 中闭包的底层原理?](https://iswbm.com/534.html)),因而,在 defer 后所修改的值会直接影响到 defer 中的 age 的值。 | ||
|
||
总结一下: | ||
|
||
1. 若 defer 后接的是单行表达式,那defer 中的 age 只是拷贝了 `func1` 函数栈中 defer 之前的 age 的值; | ||
2. 若 defer 后接的是闭包函数,那defer 中的 age 只是存储的是 `func1` 函数栈中 age 的指针。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
7.15 defer 的变量快照什么情况会失效? | ||
===================================== | ||
|
||
关于 defer 的基本知识点,我在以前的教程中有写过:\ `流程控制:defer | ||
延迟语句 <https://golang.iswbm.com/c01/c01_12.html>`__ | ||
|
||
其中有一个知识是 defer 的变量快照,举个简单的例子来说 | ||
|
||
在下面这段代码中,会先打印出来 ``18``\ ,即使后面 age 已经被改变了,可 | ||
defer 中的 age还是 修改之前的 ``0``\ ,这种现象称之为变量快照。 | ||
|
||
.. code:: go | ||
func func1() { | ||
age := 0 | ||
defer fmt.Println(age) // output: 0 | ||
age = 18 | ||
fmt.Println(age) // output: 18 | ||
} | ||
func main() { | ||
func1() | ||
} | ||
对于这个输出结果,相信还是挺容易理解的。 | ||
|
||
接下来,我请大家再看下面这个例子,可以猜猜看会输出什么? | ||
|
||
.. code:: go | ||
func func1() { | ||
age := 0 | ||
defer func() { | ||
fmt.Println(age) | ||
}() | ||
age = 18 | ||
return | ||
} | ||
func main() { | ||
func1() | ||
} | ||
正确的答案是:\ ``18``\ , 而不是 ``0`` | ||
|
||
你肯定会纳闷:不对啊,defer 不是会对变量的值做一个快照吗?答案应该是 0 | ||
啊,为什么会是 18? | ||
|
||
实际上,仔细观察,可以发现上面的两个例子的区别就在于,一个 defer | ||
后接的是单个表达式,另一个 defer | ||
后接的是一个函数,并且不是普通函数,而是一个匿名的闭包函数。 | ||
|
||
根据闭包的特性,实际上在闭包函数存的是 age | ||
这个变量的指针(原因可以查看上一篇文章:\ `Go 语言面试题 100 讲之 | ||
014篇:说说 Go | ||
中闭包的底层原理? <https://iswbm.com/534.html>`__\ ),因而,在 defer | ||
后所修改的值会直接影响到 defer 中的 age 的值。 | ||
|
||
总结一下: | ||
|
||
1. 若 defer 后接的是单行表达式,那defer 中的 age 只是拷贝了 ``func1`` | ||
函数栈中 defer 之前的 age 的值; | ||
2. 若 defer 后接的是闭包函数,那defer 中的 age 只是存储的是 ``func1`` | ||
函数栈中 age 的指针。 |
Oops, something went wrong.