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

Defer 语句用于在使用defer关键字的函数返回之前执行函数调用。

上面这个说法可能看起来比较复杂,但通过一个例子来理解就会感觉很简单。

package main

import (

"fmt"

)

funcfinished() {

fmt.Println("Finished finding largest")

}

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

}

funcmain() {

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)

}

funcmain() {

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"

)

funcprintA(a int) {

fmt.Println("value of a in deferred function", a)

}

funcmain() {

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)时就已经确定了,将当时传参的值保存到函数栈中了。到后面要调用的时候直接获取的是已经保存到栈中的值。

也就是说

funcmain() {

a := 5

defer printA(a)

a = 10

fmt.Println("value of a before deferred function call", a)

}

上面这段代码和下面这段代码结果是不同的

funcmain() {

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实践 中对其进入详细介绍。

本文转载自:迹忆客(https://www.jiyik.com)

以上是 Go 语言 defer(延迟) 关键字基本用法详解 的全部内容, 来源链接: utcz.com/z/290233.html

回到顶部