defer延迟调用

package main

import (
    "errors"
    "fmt"
    "io"
    "net/http"
    "os"
    "sync"
)

type Test struct{
    name string
}

//声明一个互斥锁
var lock sync.Mutex

var ErrDivByZero = errors.New("division by zero")

func (t *Test)Close() {
    fmt.Println(t.name, " closed")
}

func Close(t Test) {
    fmt.Println(t.name, " closed")
}

func test(x int){
    defer func() {
        msg := recover()
        fmt.Println(msg)
    }()
    defer println("a")
    defer println("b")
    defer func() {
        fmt.Println(100/x)
    }()
    defer println("c")
}

func testDeferFunc() {
    x,y := 10,20
    //延迟调用参数在注册时求值或复制
    defer func(i int) {
        fmt.Println("defer " ,i ,y)
    }(x)
    x += 10
    y += 100
    fmt.Println("x = ", x, " y = ", y)
}

func testLock() {
    lock.Lock()
    lock.Unlock()
}

func testDeferLock() {
    lock.Lock()
    defer lock.Unlock()
}

func foo() (i int) {
    i = 0
    //在延迟调用注册时求职和复制
    //out i=0
    //defer func(i int) {
    //  fmt.Println(i)
    //}(i)

    //闭包,保存外部函数的变量
    //out i=2
    defer func() {
        fmt.Println(i)
    }()
    return 2
}

func foo1(a,b int) (i int, err error) {
    defer fmt.Println("the first defer err",err)
    defer func(err error) {
        fmt.Println("the second defer err",err)
    }(err)
    defer func() {
        fmt.Println("the third defer err",err)
    }()
    if(b == 0){
        err = errors.New("divided by zero!")
        return
    }
    i = a/b
    //这种return会将相应的返回值进行返回
    return
}

func testRun() {
    var run func() = nil
    defer run()
    fmt.Println("runs")
}

func do() error {
    //发起get请求
    res, err := http.Get("http://www.google.com")
    defer res.Body.Close()
    if err != nil {
        return err
    }

    //

    return nil
}

func do1() error {
    res, err := http.Get("http://www.google.com")
    if res != nil {
        defer res.Body.Close()
    }
    if err != nil {
        return err
    }
    //code
    return nil
}

func  doFile() error {
    f, err := os.Open("a.txt")
    if err != nil {
        fmt.Println(err)
        return err
    }
    ////由于文件关闭时也会出现错误,所以在使用defer进行延迟关闭
    //if f != nil {
    //  defer f.Close()
    //}

    if f != nil {
        defer func(){
            if err := f.Close(); err != nil {

            }
        }()
    }
    return nil
}

func doFile1() (err error) {
    f, err := os.Open("a.txt")
    if err != nil {
        return err
    }
    if f != nil {
        defer func() {
            if ferr := f.Close(); ferr != nil {
                err = ferr
            }
        }()
    }

    return nil
}

func doFileClose() error {
    f, err := os.Open("book.txt")
    if err != nil {
        return err
    }
    if f != nil {
        defer func(f io.Closer) {
            if err := f.Close(); err != nil {
                fmt.Printf("defer close book.txt err %v\n",err)
            }
        }(f)
    }

    f, err = os.Open("another_book.txt")
    if err != nil {
        return err
    }

    if f != nil {
        defer func(f io.Closer) {
            if err := f.Close(); err != nil {
                fmt.Printf("defer close another_book.txt err %v\n",err)
            }
        } (f)
    }

    return nil
}

func deferpanic() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    var ch chan int = make(chan int, 10)
    close(ch)
    ch <- 1
}

func testPanic() {
    //如果有多个panic指挥捕获最后的panic
    defer func() {
        fmt.Println(recover())
    }()

    defer func() {
        panic("defer panic")
    }()

    panic("test panic")
}

//捕获函数recover只有在延迟函数内直接调用才有效
func testRecover() {
    //捕获函数只有在延迟函数内直接调用才会有效
    defer func() {
        fmt.Println("defer func")
        fmt.Println(recover())
    }()

    defer recover()//无效
    defer fmt.Println(recover())//无效
    defer func() {
        //err := recover()
        //fmt.Println(err)
        func() {
            fmt.Println("defer recover")//虽然执行了但是recover未执行
            recover()//无效
        }()
    }()
    panic("test panic")
}

func div(x,y int)(int, error){
    if y == 0 {
        return 0, ErrDivByZero
    }
    z := x/y
    return z, nil
}

func divRecover() {
    defer func() {
        fmt.Println(recover())
    }()

    switch z,err := div(10, 0); err {
    case nil:
        fmt.Println(z)
    case ErrDivByZero:
        fmt.Println(err)
    }
}

func main() {
    //ts := []Test{{"a"}, {"b"} ,{"c"}}
    //for _,t := range ts {
    //  //1
    //  //由于t为局部变量,且为同一个变量,当从ts中读出值的时候,t最终会保留最后一个对象的引用
    //  //所以输出结果总是c closed
    //  //此时的t相当于this指针
    //  //defer t.Close()
    //  //2
    //  //对于将struct作为函数参数而言,go再进行函数调用时,会将参数的拷贝保存起来,执行defer时自然就正确了
    //  //defer Close(t)
    //  //3
    //  //使用t1对t进行拷贝之后再次defer时,t1保存了当前层的引用
    //  t1 := t
    //  defer t1.Close()
    //}
    //test(0)
    //testDeferFunc()

    //滥用defer可能导致性能问题
    //func() {
    //  t1 := time.Now()
    //  for i:=0;i<10000;i++ {
    //      testLock()
    //  }
    //  elapsed := time.Since(t1)
    //  fmt.Println("testLock elapsed = ", elapsed)
    //} ()
    //
    //func() {
    //  t2 := time.Now()
    //  for i:=0;i<10000;i++ {
    //      testDeferLock()
    //  }
    //  elapesd := time.Since(t2)
    //  fmt.Println("testDeferLock elapsed = ", elapesd)
    //} ()
    //
    //foo()
    //
    //foo1(1,0)

    //defer func() {
    //  if err := recover(); err != nil {
    //      fmt.Println("error: ", err)
    //  }
    //}()
    //testRun()

    //do()
    //do1()
    //doFile()
    //doFile1()
    //err := doFileClose()
    //fmt.Println(err)

    //向已经关闭的通道发送数据抛出异常
    //deferpanic()

    //testPanic()
    //testRecover()

    divRecover()
}




©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,695评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,863评论 1 6
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,503评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 2,570评论 2 9