go defer注意点,很容易出错的!!!

1:defer是在return之前执行的  函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中

返回值 = xxx
调用defer函数
空的return

func f() (result int) {
     result = 0  //return语句不是一条原子调用,return xxx其实是赋值+ret指令
     func() { //defer被插入到return之前执行,也就是赋返回值和ret指令之间
         result++
     }()
     return
}

func f() (r int) {
     t := 5
     r = t //赋值指令
     func() {        //defer被插入到赋值与返回之间执行,这个例子中返回值r没被修改过
         t = t + 5
     }
     return        //空的return指令
}

2:有名返回值和匿名返回值的问题
匿名返回值是在 return 执行时被声明,有名返回值则是在函数声明的同时被声明,因此在 defer 语句中只能访问有名返回值,而不能直接访问匿名返回值

此方法返回的是2 而不是1 之前在这困扰了好久,就是没弄明白对匿名返回值的函数是无法修改该返回值的,匿名返回值相当于又重新赋值了一个新的变量

func det2() int {

    result := 2

    println(&result)

    defer func(result *int) {

        println("det2")

        *result = 1

        println(*result)

    }(&result)#所以对result无论如何修改都无法改变返回值的内容

    #可变形为

   匿名变量 = result

    return 匿名变量 

}

相反的 defer修饰的有名返回值的函数可以修改最后的返回值内容
func b() (i int) {
 defer func() {
  i++
  fmt.Println("b defer2:", i) // 打印结果为 b defer2: 2
 }()
 defer func() {
  i++
  fmt.Println("b defer1:", i) // 打印结果为 b defer1: 1
 }()
 return i // 或者直接 return 效果相同
}   
最终返回的结果i为2 ,若果将上述函数变为匿名返回值
 
func b() {
 defer func() {
  i++
  fmt.Println("b defer2:", i) // 打印结果为 b defer2: 2
 }()
 defer func() {
  i++
  fmt.Println("b defer1:", i) // 打印结果为 b defer1: 1
 }()
 return // 或者直接 return 效果相同
}  此时返回值为 0


3:defer 调用的函数参数的值在 defer 定义时就确定了, 而 defer 函数内部所使用的变量的值需要在这个函数运行时才确定
func f1() (r int) {
    r = 1
    defer func() {
        r++
        fmt.Println(" r value = ",r)
    }()
    r = 2
    return
}



参考:https://www.jb51.net/article/127130.htm
posted @ 2018-12-25 10:44  kakaok  阅读(355)  评论(0编辑  收藏  举报