扫码订阅《 Go语言基础》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • 课程介绍

    • 《Go语言基础》
  • 入门简介

  • 基础语法

  • 流程语句

  • 数组和切片

  • Map

  • string

  • 函数

    • 第1节:函数
    • 第2节:函数的参数
    • 第3节:函数的返回值
    • 第4节:函数中变量的作用域
    • 第5节:defer
    • 第6节:高阶函数
  • 指针

  • 结构体

  • 方法

  • 接口

  • 错误

扫码订阅《 Go语言基础》或入驻星球,即可阅读文章!

第5节:defer


GOLANG ROADMAP

# 1.1 延迟是什么?

即延迟(defer)语句,延迟语句被用于执行一个函数调用,在这个函数之前,延迟语句返回。

# 1.2 延迟函数

你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题

  • 如果有很多调用defer,那么defer是采用后进先出模式
  • 在离开所在的方法时,执行(报错的时候也会执行)
func ReadWrite() bool {
    file.Open("file")
    defer file.Close()
    if failureX {
          return false
    } 
    if failureY {
          return false
    } 
    return true
}
1
2
3
4
5
6
7
8
9
10
11

最后才执行file.Close()

示例代码:

package main

import "fmt"

func main() {
    a := 1
    b := 2
    defer fmt.Println(b)
    fmt.Println(a)
}
1
2
3
4
5
6
7
8
9
10

运行结果:

1
2
1
2

示例代码:

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)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

运行结果:

Started finding largest  
Largest number in [78 109 2 563 300] is 563  
Finished finding largest 
1
2
3

# 1.3 延迟方法

延迟并不仅仅局限于函数。延迟一个方法调用也是完全合法的。让我们编写一个小程序来测试这个。

示例代码:

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 ")  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

运行结果:

Welcome John Smith 
1

# 1.4 延迟参数

延迟函数的参数在执行延迟语句时被执行,而不是在执行实际的函数调用时执行。

让我们通过一个例子来理解这个问题。

示例代码:

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)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

运行结果:

value of a before deferred function call 10  
value of a in deferred function 5 
1
2

# 1.5 堆栈的推迟

当一个函数有多个延迟调用时,它们被添加到一个堆栈中,并在Last In First Out(LIFO)后进先出的顺序中执行。

我们将编写一个小程序,它使用一堆defers打印一个字符串。示例代码:

package main

import (  
    "fmt"
)

func main() {  
    name := "Naveen"
    fmt.Printf("Orignal String: %s\n", string(name))
    fmt.Printf("Reversed String: ")
    for _, v := range []rune(name) {
        defer fmt.Printf("%c", v)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

运行结果:

Orignal String: Naveen  
Reversed String: neevaN 
1
2

# 1.6 defer注意点

defer函数:
当外围函数中的语句正常执行完毕时,只有其中所有的延迟函数都执行完毕,外围函数才会真正的结束执行。
当执行外围函数中的return语句时,只有其中所有的延迟函数都执行完毕后,外围函数才会真正返回。
当外围函数中的代码引发运行恐慌时,只有其中所有的延迟函数都执行完毕后,该运行时恐慌才会真正被扩展至调用函数。
1
2
3
4
  • 1.1 延迟是什么?
  • 1.2 延迟函数
  • 1.3 延迟方法
  • 1.4 延迟参数
  • 1.5 堆栈的推迟
  • 1.6 defer注意点