golang 中的 defer 与 return

文章目录 (?) [+]

    需要说明 2 点

    1. return 的执行包含两步:

        第一步给返回值赋值,匿名返回值先在此声明再赋值,而有名返回值是函数声明时声明的,在此直接赋值;

        第二步调用 RET 返回指令并传入返回值,在执行 RET 返回指令时会先检查是否存在 defer 语句 ,若存在则按“先进后出”依次执行,再将返回值带出退出函数


    2. defer 声明时会先确定参数的值,defer 推迟执行的仅是其函数体


    package main
    
    import (
        "fmt"
    )
    
    func testA() int {
        fmt.Println("-------------------testA")
        var i int
    
        defer func() {
            i++
            fmt.Println("A#1", i)
        }()
    
        defer func() {
            i++
            fmt.Println("A#2", i)
        }()
    
        fmt.Println("A#3", i)
    
        // 第一步:匿名返回值先声明再赋值,声明匿名返回值后将 i 值传递给匿名返回值
        // 第二步:检查是否存在 defer 语句,存在则逆序执行,虽然 defer 里修改了 i 的值,但由于为匿名返回值的值是通过 i 值传递获得的,故 i 的值修改不会影响匿名返回值的值
        return i
    }
    
    func testB() *int {
        fmt.Println("-------------------testB")
        i := 2
    
        // defer 声明时会先确定参数的值,defer 推迟执行的仅是其函数体
        // 故此处声明时会有 j = 2, k = 0
        defer func(j, k int) {
            i++
            fmt.Println("B#1", i, &i)
            fmt.Println("B#2", j)
            fmt.Println("testA", k)
        }(i, testA())
    
        fmt.Println("B#5", i, &i)
    
        // 第一步:匿名返回值先声明再赋值,声明匿名返回值后将 i 地址传递给匿名返回值
        // 第二步:检查是否存在 defer 语句,存在则逆序执行,defer 里修改了 i 的值,由于匿名返回值的地址指向 i 的地址,故匿名返回值的值同 i 的值一致
        return &i
    }
    
    func testC() (i int) {
        fmt.Println("-------------------testC")
    
        defer func() {
            i++
            fmt.Println("C#1", i, &i)
        }()
    
        i = 5
    
        fmt.Println("C#2", i, &i)
    
        // 第一步:有名返回值则直接赋值,此处的返回值在函数声明时已然声明为 i
        // 第二步:检查是否存在 defer 语句,存在则逆序执行,defer 里修改了 i 的值,也即返回值
        return 8
    }
    
    func main() {
        defer func() {
            fmt.Println("D#1")
            if err := recover(); err != nil {
                fmt.Println(err)
            }
        }()
    
        ptr := testB()
        fmt.Println("testB", *ptr, ptr)
        fmt.Println("testC", testC())
    
        panic("D#2")
    }

    运行结果为

    -------------------testB
    -------------------testA
    A#3 0
    A#2 1
    A#1 2
    B#5 2 0xc00001e0a8
    B#1 3 0xc00001e0a8
    B#2 2
    testA 0
    testB 3 0xc00001e0a8
    -------------------testC
    C#2 5 0xc00001e0f0
    C#1 9 0xc00001e0f0
    testC 9
    D#1
    D#2


    本文标题:golang 中的 defer 与 return
    本文链接:https://lanseyujie.com/post/golang-defer-statement.html
    版权声明:本文使用「署名 4.0 国际」创作共享协议,转载或使用请遵守署名协议。
    点赞 0 分享 0