go语言之defer

Beginner18 · · 2326 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

/*1 适用于函数和方法,只能跟方法或者函数
*/
/*2 defer语句延迟执行直到函数return或者panic
return函数不是原子级,包括写入返回参数及
函数返回,defer语句在写入返回参数后函数返
回前执行
*/
/*3 defer语句反顺序执行(栈)一般用于成对
打开、关闭、连接、断开连接、加锁、释放锁
释放资源
*/
/*4 defer语句所在处变量入栈,只是函数结束再处理
    该语句,若值传递则后续值改变不影响defer语句,
    若地址传递则影响defer语句
    defer函数参数在defer语句执行时初始化
    defer函数调用时具体执行
4.1 defer记录函数的进入和退出,trace函数
*/
/*5 方法为一种数据类型,方法定义后,通过赋值给具有方法的
数据类型,则方法的类型与赋值类型一致,可以执行方法操作
*/
/*6 Each time a "defer" statement executes, the function value
and parameters to the call are evaluated as usualand saved anew
but the actual function is not invoked.
anew: 重新再
*/
/*7 defer函数调用函数返回值与函数输入参数按正常函数处理(复制新参数),
闭包函数变量更新defer函数中变量更新,但实际函数没有激活。
*/
/*8 函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,
最后才是返回到调用函数中。利用闭包defer函数(指针)可修改返回值的值.
*/
/*9 defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,
修改返回值,使最终的函数返回值与你想象的不一致
*/
/*10 defer+panic
无panic的函数按defer正常执行: defer定义,func return/panic执行
defer
panic 的函数仅执行panic之后语句不执行
*/
//
package main

import (
    "fmt"
    "log"
    "time"
)

//定义方法
type defMeth struct {
    err bool
    str string
}
//定义接口,接口为一种数据类型,提供操作
type in interface {
    ini()
    prinOut()
}

func (def *defMeth) ini() {
    def.err = true
    def.str = "hei"
}
func (def *defMeth) prinOut() {
    fmt.Println("just print: ", def)
}

type defError struct {
    err error
    str string
}

func (def *defError) ini() {
    def.err = fmt.Errorf("this is an err: %s\n", "true")
    def.str = "this is a bug"
}
func (def *defError) prinOut() {
    fmt.Println("just print: ", def)
}
func main() {
    var s1 defMeth
    var s2 defError
    var def in
    a := 1
    //defer+闭包处理, a为主函数变量,a值变化该defer函数变量会更新
    defer func() { fmt.Println("close package, test the value of a:", a) }()
    defer fmt.Println("fmt a is: ", a)
    //值传递,defer函数入栈,变量值已赋值,只是最后执行
    defer func(a int) { fmt.Println("no name func a is: ", a) }(a)
    //地址传递:传递的为地址,若地址处值改变则操作值改变,map传递的地址
    defer func(a *int) { fmt.Println("no name func a address is: ", *a) }(&a)
    //为接口赋值变量类型及变量地址
    def = &s1
    //a:=1
    def.ini()
    //defer a=2 //错误defer后必须是函数或者方法或者接口
    def.prinOut()
    //fmt.Println("result", bigSlowOperation())
    //接口
    def = &s2
    def.ini()
    //函数中嵌套defer改变defer执行顺序,函数中defer按栈执行,该函数正常执行
    def.prinOut()
    a++
    fmt.Println(a)
    fmt.Println("the value of bigSlow func: ", bigSlowOperation())
    //10 test defer panic
    deferPanic()

}
func bigSlowOperation() int {
    log.Printf("main starts %s", "\n")
    i := 1
    //非匿名函数调用参数i已确定:1
    //defer fmt.Println(i)
    //匿名函数可调用返回值:2
    defer func() { fmt.Println(i) }()
    defer trace("bigSlowOperation")() // don't forget the
    //extra parentheses
    // ...lots of work…
    time.Sleep(10 * time.Second) // simulate slow operation
    //by sleeping
    i++
    return i
}

//返回值为函数,函数需要正常入栈,
//函数输入参数及返回地址按正常函数处理,
//defer trace("")()
//函数为trace中包装的匿名函数,需正常处理该函数,
//的形参及返回地址
func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() {
        log.Printf("exit %s (%s)", msg, time.Since(start))
    }
}
//10 defer+panic: what happends after a defer func panic
func deferPanic() {
    //正常执行
    defer fmt.Println("the last defer panic func")
    defer fmt.Println("the 3st defer panic func")
    //panic func 仅执行panic语句
    defer func() { panic("test defer panic"); fmt.Println("the func panics") }()
    //正常执行
    defer fmt.Println("the 2st defer panic func")
    defer fmt.Println("the 1st defer panic func")
}

 


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2326 次点击  ∙  1 赞  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传