Go 语言编程 —— Defer 概念

幸运草
幸运草
幸运草
1033
文章
3
评论
2020年4月13日01:28:00
评论
310

什么是 Defer

延迟执行 Defer 语句用于在当前的 Defer 语句返回之前执行一个函数调用。文字不好理解,直接上代码,更容易理解一点。

package main

import "fmt"

func main() {
    sayHi("Boyce")
}

func sayHi(name string) {
defer sayBye()
    fmt.Println("Hi", name)
    fmt.Println("bla bla bla ...")
}

func sayBye() {
    fmt.Println("bye bye . . .")
}
这段代码很简单,和某某 sayHi 打招呼。现在这种特殊时期,出门必须戴口罩,遇人保持距离,减少接触,抓到了一个程序 bla bla bla 一顿唠。sayHi 里面的第一行代码是 defer sayBye(),看上去这个完全符合当下的疫情要求,不要聚集,看下实际输出:
// go run .deferSayHi.go
Hi  Boyce
bla bla bla ...
bye bye . . .

Defer 方法

Defer 不仅能用于上面的 function ,也可以用于下面的 method

package main

import "fmt"

type msg struct {
	sender  string
	subject string
	content string
}

func (m msg) msgInfo() {
	fmt.Println("subject:", m.subject)
	fmt.Println("from:", m.sender)
	fmt.Println("content is :", m.content)
}

func main() {
	m := msg{
		sender:  "Boyce",
		subject: "error log",
		content: "your site is down",
	}
defer m.msgInfo()
	fmt.Println("ding ding ding, you have a new alert ...")
}


// go run .deferMethod.go
ding ding ding, you have a new alert ...
subject: error log
from: Boyce
content is : your site is down

Defer 参数的计算

延迟函数的参数是在执行 defer 语句时求值,而不是在实际函数调用完成时求值。

用代码再解释一下:

package main

import "fmt"

func printDefer(input int) {
    fmt.Println("the value in defer is", input)
}

func main() {
    a := 2
defer printDefer(a)
    a = 10
    fmt.Println("the value before defer is", a)
}
上面的程序中,a 最初的值是 2。接着下面一行 defer 函数,当时 a 的值是 2,但是函数被延迟执行。下面再给 a 重新赋值为 10,接着输出 a 的值。实际输出如下:
// go run .deferParamCal.go
the value before defer is 10
the value in defer is 2
从输出结果我们不难看出,虽然 a 在 defer 语句之后(执行之前)被重新赋值,但,实际上 defer 使用的还是其语句前面“当时的” a 值。

多 Defer 的执行顺序

一个函数中有多个 defer 的时候,这些 defer 被放入堆栈(stack)中,所以,多个 defer 的执行顺序是 LIFO(后进先出)。
下面还是直接上代码解释:
package main

import "fmt"

func main() {
    sayHi("Boyce")
}

func sayHi(name string) {
for _, v := range []rune(name) {
defer fmt.Printf("%c", v)
    }
defer fmt.Println("I think your reversed name is ...")
    fmt.Println("Hi", name)
}
上面的程序中,将 defer fmt.Printf("%c", v) 放到了循环里面,他们在堆栈(stack)中应该是:
defer fmt.Printf("%c", e)
defer fmt.Printf("%c", c)
defer fmt.Printf("%c", y)
defer fmt.Printf("%c", o)
defer fmt.Printf("%c", B)
defer fmt.Println("I think your reversed name is ...")
上面的模拟了 defer 在堆栈(stack)中的顺序,堆栈(stack)是一种后进先出的数据结构。对于我们的例子来说,也就是 defer fmt.Printf("%c", e) 应该被最先执行,最终的结果就是,字符串被反转输出。
//go run .deferStack.go
Hi Boyce
I think your reversed name is ...
ecyoB

总结

Defer 用于确保在程序执行的后期执行函数调用,通常用于清理。defer 通常用于其他语言中,例如 ensure和 finally。
关于 defer 的实际应用,待学成归来,再补充。 

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

转载请注明:{{title}}-变化吧
  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 赞助本站
  • 支付宝扫一扫
  • weinxin
幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...