Skip to content

Commit

Permalink
新增文章
Browse files Browse the repository at this point in the history
  • Loading branch information
iswbm committed Sep 3, 2021
1 parent f8bb58f commit 7862c4b
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 631 deletions.
54 changes: 54 additions & 0 deletions source/c07/c07_15.md
@@ -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 的指针。
66 changes: 66 additions & 0 deletions source/c07/c07_15.rst
@@ -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 的指针。

0 comments on commit 7862c4b

Please sign in to comment.