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
    //延遲調用參數(shù)在注冊時求值或復制
    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)

    //閉包,保存外部函數(shù)的變量
    //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 {
    //發(fā)起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
    }
    ////由于文件關閉時也會出現(xiàn)錯誤,所以在使用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")
}

//捕獲函數(shù)recover只有在延遲函數(shù)內直接調用才有效
func testRecover() {
    //捕獲函數(shù)只有在延遲函數(shù)內直接調用才會有效
    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")//雖然執(zhí)行了但是recover未執(zhí)行
            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作為函數(shù)參數(shù)而言,go再進行函數(shù)調用時,會將參數(shù)的拷貝保存起來,執(zhí)行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)

    //向已經關閉的通道發(fā)送數(shù)據(jù)拋出異常
    //deferpanic()

    //testPanic()
    //testRecover()

    divRecover()
}




?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 夜鶯2517閱讀 128,103評論 1 9
  • 版本:ios 1.2.1 亮點: 1.app角標可以實時更新天氣溫度或選擇空氣質量,建議處女座就不要選了,不然老想...
    我就是沉沉閱讀 7,377評論 1 6
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,822評論 28 54
  • 兔子雖然是枚小碩 但學校的碩士四人寢不夠 就被分到了博士樓里 兩人一間 在學校的最西邊 靠山 兔子的室友身體不好 ...
    待業(yè)的兔子閱讀 2,765評論 2 9

友情鏈接更多精彩內容