迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Go >

Go 语言 defer(延迟) 关键字基本用法详解

作者:迹忆客 最近更新:2023/01/08 浏览次数:

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() 函数返回之前被调用。 运行这个程序,我们可以看到下面的输出。

go defer example

largest() 函数开始执行并打印上述输出结果的前两行。 在它可以返回之前,我们的 defer 函数完成执行并打印文本“Finished finding largest”:)

从上面的示例中我们可以看到,defer 语句不管是在函数中的什么位置,都会在该函数中其他代码执行完之后,函数返回之前才执行。defer finished() 语句是在 largest() 函数中的最开始的位置,但是我们发现它是在最后执行的。

 

Go defer 代码执行顺序
Go defer 代码执行顺序

 

延迟方法

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()

上面程序运行结果如下

go defer method示例

参数评估

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)

}

运行示例

上面的代码输出结果如下

go defer 函数参数

通过上面的代码我们看到 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实践 中对其进入详细介绍。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

使用 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 ALLOWED_HOSTS 介绍

发布时间:2023/05/04 浏览次数:181 分类:Python

本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。

Django 中的 Select_related 方法

发布时间:2023/05/04 浏览次数:129 分类:Python

本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。

在 Django 中上传媒体文件

发布时间:2023/05/04 浏览次数:198 分类:Python

在本文中,我们简要介绍了媒体文件以及如何在 Django 项目中操作媒体文件。

Django 返回 JSON

发布时间:2023/05/04 浏览次数:106 分类:Python

在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。

在 Django 中创建对象

发布时间:2023/05/04 浏览次数:59 分类:Python

本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便