延迟和命名的返回值如何在golang中起作用?

时间:2016-05-16 07:36:34

标签: go

我刚刚开始学习golang,我对golang博客帖子here中使用defer更改命名返回值的一个例子感到困惑。

例子说:

  
      
  1. 延迟函数可以读取并分配给返回函数的命名返回值。
  2.         

    在此示例中,延迟函数在周围函数返回后递增返回值i。因此,此函数返回2

func c() (i int) {
    defer func() { i++ }()
    return 1
}

但正如我从A Tour of Go - Named return values

所学到的
  

不带参数的return语句返回指定的返回值。这被称为“裸体”回归。

我在下面的代码和函数b中进行了测试,它返回1,因为它不是上面提到的没有参数的返回语句

func a() (i int) { // return 2
    i = 2
    return
}

func b() (i int) {  // return 1 
    i = 2
    return 1
}

所以我的问题是在第一个例子中,周围的函数c有一个命名的返回值i,但函数c使用 return 1 ,在第二个例子中我们可以看到它应该返回1不管我是什么价值。但是为什么在我更改延迟函数后,c函数返回i的值而不是值1?

在我输入问题时,我可能已经猜到了答案。是因为

return 1 

等于

i = 1
return 

在具有命名返回值变量i的函数中?

请帮我确认一下,谢谢!

3 个答案:

答案 0 :(得分:30)

  

defer语句将函数调用推送到列表中。在周围函数返回后执行已保存调用的列表。 - The Go Blog: Defer, Panic, and Recover

了解上述陈述的另一种方法:

  

延迟语句函数调用推送到堆栈。在周围函数返回之前,会立即调用已保存的调用弹出(LIFO)和延迟函数的堆栈。

 func c() (i int) {
    defer func() { i++ }()
    return 1
}

返回1后,延迟func() { i++ }()被执行。因此,按执行顺序:

  1. i = 1(返回1)
  2. i ++(推迟func从堆栈中弹出并执行)
  3. i == 2(命名变量i的最终结果)
  4. 为了理解:

     func c() (i int) {
        defer func() { fmt.Println("third") }()
        defer func() { fmt.Println("second") }()
        defer func() { fmt.Println("first") }()
    
        return 1
    }
    

    执行令:

    1. i = 1(返回1)
    2. “第一”
    3. “第二”
    4. “第三”

答案 1 :(得分:5)

我认为混淆是关于功能的功能如果你这样分类怎么样:

  func main() {
      fmt.Println(c()) //the result is 5
  }

  // the c function returned value is named j
  func c() (j int)  {
      defer changei(&j)
      return 6
  }
  func changei(j *int) {
      //now j is 6 because it was assigned by return statement 
      // and if i change guess what?! i changed the returned value
      *j--;
  }

但如果返回值的名称不是这样的:

  func main() {
      fmt.Println(c()) //the result will become 6
  }

  // the c function returned value is not named at this time
  func c() int  {
      j := 1
      defer changei(&j)
      return 6
  }
  func changei(j *int) {
      //now j = 1
      // and if i change guess what?! it will not effects the returned value
      *j--;
  }

我希望这会清除混乱,这就是我如何快乐的Go编码

答案 2 :(得分:4)

根据Go规范:

Return Statements 指定结果的“return”语句在执行任何延迟函数之前设置结果参数。

Defer Statements “...在周围函数返回之前立即调用延迟函数......”

所以是的,正如您所假设的那样,指定了返回变量,然后延迟语句递增它。

我想补充说,命名的返回参数会导致细微的错误,除非别无选择,否则通常应该避免。