Skip to main content

24. 执行顺序控制:Defer 延迟

yaklang支持defer关键字,和常见的defer关键字相同,能够实现在退出代码块的时候执行指定代码的能力。

yaklang支持匿名函数,所以一个很常见的写法是

defer fn(){
}()
defer fn{
}

如果读者有go语言的使用经历,那么就很容易上手,不过yaklang的defer和go的defer还是有一定的区别。

变量参数#

在go里defer里要使用指定变量,可以使用两种方式:

  1. 传入参数,这种方式defer内部的变量不会随外部的变量变化而变化
//go 函数传参模式func dfp1() {   var a = 1   defer func(t int) {        fmt.Println(t)   }(a)   a = 2   return}
func main() {    dfp1()}
/*OUTPUT1*/
  1. 直接使用代码块内部的参数,这种方式defer内部的变量会随外部的变量变化而变化
//go 直接使用作用域内的变量func dfp2() {   var a = 1    defer func(){        fmt.Println(a)    }()   a = 2   return}
func main() {    dfp2()}
/*OUTPUT2*/

而对于yaklang来说,无论使用哪一种方法,defer内变量都会随着外部变量的变化而变化

f = 1defer func{    println("准备开始执行 defer func")    println(1) // 等到执行这里的时候,就会报错}println("设置 f 变量为空")f = nil // 在这里设置 f 为空

/*OUTPUT设置 f 变量为空准备开始执行 defer func<nil>*/

defer与返回值#

在go语言中,当返回值在函数定义里就声明了的情况下,defer是可以修改返回值的。

func test() (i int) {   i = 1   defer func() {      i++   }()   return i}
func main() {   fmt.Println("return:", test())}/*OUTPUTreturn: 2*/

而在yaklang中,无论采用何种方式,defer都不会影响到返回值。

defer的执行顺序#

yaklang的defer的执行顺序和go的一致,采用的是"先进后出"的栈结构

defer fn {    dump(2)}
defer fn(){    dump(1)}()
/* OUTPUT:(int) 1(int) 2*/