defer/panic

defer

1.defer语句后面必须是函数调用,不能是语句,例如:

func hello() {
    fmt.Println("hello")
}
func getString() string {
    defer func(x int) {
        fmt.Println(x)
    }(1)
    defer hello()
    return "abd"
}

2.defer语句执行的函数在本函数执行完毕后执行
3.每次defer语句执行的时候,会把函数“压栈”,函数参数会被拷贝下来,在return前会按照出栈顺序执行这些函数,而执行这些函数的参数值可以是defer时的值,也可以是执行函数时的值,这主要看defer的是一个闭包还是一个函参传递,如果是函参传递,则值确定好了,如果是一个闭包则使用外部值,即最后确定的外部值。
4.defer函数执行的顺序:
1. 先给返回值赋值
2. 执行defer语句
3. 包裹函数return返回
举例:

func f1() int { //匿名返回值
    var r int = 6
    defer func() {
            r *= 7
    }()
    return r
} //这里返回6,先复制r = 6然后执行defer语句
func f2() (r int) { //有名返回值
    defer func() {
        r *= 7
    }()
    return 6
}//这里返回42 
func f3() (r int) { //有名返回值
    defer func(r int) {
        r *= 7
    }(r)
    return 6
}//这里返回6

f1的结果是6。f1是匿名返回值,匿名返回值是在return执行时被声明,因此defer声明时,还不能访问到匿名返回值,defer的修改不会影响到返回值。
f2先给返回值r赋值,r=6,执行defer语句,defer修改r, r = 42,然后函数return。
f3是有名返回值,但是因为r是作为defer的传参,在声明defer的时候,就进行参数拷贝传递,所以defer只会对defer函数的局部参数有影响,不会影响到调用函数的返回值。

panic

1.panic不仅可以传入string,也可以传入别的类型,例如

panic("panic!!!") //输出panic: panic!!!
panic([]int{1, 2}) //输出panic: ([]int) (0x49be80,0xc0000b6000)

你可能感兴趣的:(defer/panic)