Go 语言 defer(延迟) 关键字基本用法详解
Defer 语句用于在使用defer关键字的函数返回之前执行函数调用。
上面这个说法可能看起来比较复杂,但通过一个例子来理解就会感觉很简单。
package main
import (
"fmt"
)
func finished() {
fmt.Println("Finished finding largest")
}
func largest(nums []int) {
defer finished()
fmt.Println("Started finding largest")
max := nums[0]
for _, v := range nums {
if v > max {
max = v
}
}
fmt.Println("Largest number in", nums, "is", max)
}
func main() {
nums := []int{78, 109, 2, 563, 300}
largest(nums)
}
上面是一个简单的程序,用于查找给定的整数切片的最大值。 函数 largest()
将一个 int 切片作为参数并打印该切片的最大数字。 largest() 函数的第一行包含语句 defer finished()
。 这意味着 finished() 函数将在 largest() 函数返回之前被调用。 运行这个程序,我们可以看到下面的输出。
largest() 函数开始执行并打印上述输出结果的前两行。 在它可以返回之前,我们的 defer 函数完成执行并打印文本“Finished finding largest”:)
从上面的示例中我们可以看到,defer 语句不管是在函数中的什么位置,都会在该函数中其他代码执行完之后,函数返回之前才执行。defer finished()
语句是在 largest() 函数中的最开始的位置,但是我们发现它是在最后执行的。
延迟方法
Defer 不仅限于函数。也可以在方法前面使用。我们来看一下下面这段代码
package main
import (
"fmt"
)
type person struct {
firstName string
lastName string
}
func (p person) fullName() {
fmt.Printf("%s %s",p.firstName,p.lastName)
}
func main() {
p := person {
firstName: "John",
lastName: "Smith",
}
defer p.fullName()
fmt.Printf("Welcome ")
}
在上面的代码中,我们在结构体 person 的方法 fullName() 前使用了defer关键字—— defer p.fullName()
。
上面程序运行结果如下
参数评估
defer 函数的参数在执行 defer 语句时计算,而不是在实际函数调用完成时计算。
要怎么理解这句话呢? 老样子,我们还是先通过一段代码来理解
package main
import (
"fmt"
)
func printA(a int) {
fmt.Println("value of a in deferred function", a)
}
func main() {
a := 5
defer printA(a)
a = 10
fmt.Println("value of a before deferred function call", a)
}
上面的代码输出结果如下
通过上面的代码我们看到 defer printA(a)
在执行的时候参数 a 的值就已经确定了,而不是等到函数printA()执行的时候才去确定当前a的值。
我们通过之前的介绍知道 defer 语句不管是放在函数内部的什么位置,由defer修饰的函数或者方法都是在包含它的函数中的其他语句执行完成之后,在函数返回之前才会去调用。然而,虽说是最后调用,但是它的参数是早在内核执行 defer printA(a)时就已经确定了,将当时传参的值保存到函数栈中了。到后面要调用的时候直接获取的是已经保存到栈中的值。
也就是说
func main() {
a := 5
defer printA(a)
a = 10
fmt.Println("value of a before deferred function call", a)
}
上面这段代码和下面这段代码结果是不同的
func main() {
a := 5
a = 10
defer printA(a)
fmt.Println("value of a before deferred function call", a)
}
虽说 printA(a) 被调用的位置是相同的。
到这我们应该可以理解,虽然在执行 defer 语句后 a 的值变为 10,但实际的调用延迟函数 printA(a) 时仍然打印 5。
本篇我们对Go defer的基本用法进行了介绍,在下一篇 深入理解 defer关键字及defer实践 中对其进入详细介绍。
相关文章
使用 C 语言中的 goto 语句
发布时间:2023/05/07 浏览次数:79 分类:C语言
-
本文介绍了如何在 C 语言中使用 goto 语句。使用 goto 语句在 C 语言中实现循环 goto 关键字是 C 语言的一部分,它提供了一个做无条件跳转的结构。
Django 中的 Slug
发布时间:2023/05/04 浏览次数:173 分类:Python
-
本篇文章旨在定义一个 slug 以及我们如何使用 slug 字段在 Python 中使用 Django 获得独特的帖子。
在 Django 中按降序过滤查询集中的项目
发布时间:2023/05/04 浏览次数:157 分类:Python
-
在这个讲解中,学习如何借助 Django 中的 order_by() 方法按降序过滤出查询集中的项目。
Django ALLOWED_HOSTS 介绍
发布时间:2023/05/04 浏览次数:181 分类:Python
-
本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。
Django 中的 Select_related 方法
发布时间:2023/05/04 浏览次数:129 分类:Python
-
本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。
使用 Post 请求将数据发送到 Django 服务器
发布时间:2023/05/04 浏览次数:159 分类:Python
-
在这篇关于Django的讲解中,我们简要介绍了post和get请求以及如何在Django中用post实现CSRF token。
Django 返回 JSON
发布时间:2023/05/04 浏览次数:106 分类:Python
-
在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。
在 Django 中创建对象
发布时间:2023/05/04 浏览次数:59 分类:Python
-
本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。