为什么在Golang的封闭体后添加“()”?

我正在阅读The Go Programming Language Specifications ,发现自己在封闭体之后没有真正理解“()”:

Function literals

func(ch chan int){ch < – ACK} (replyChan) `

Defer statements的例子中:

 // f returns 1 func f() (result int) { defer func() { result++ }() // why and how? return 0 } 

我不清楚在封闭体之后添加和使用“()”的原因,希望有人能够解释清楚。

这不是()必须在(仅) 封闭后添加。 推迟语句的语言规范要求它的“expression式” 总是一个函数调用。

为什么呢? 这与其他function一样,在“推迟”或不推迟:

考虑:

 func f() int { return 42 } 

 a := f 

VS

 b := f() 

第一个expression式RHS是一个函数值。 在第二个版本中,RHS是函数返回的值即函数调用。

所以是的语义:

 defer f 

VS

 defer f() 

除了第一个版本在“推迟”的情况下是没有意义的,因此规范提到它必须是第二种forms(仅)。

这是恕我直言,也更容易学习,因为与上述讨论函数调用之外的'延迟'陈述的正交性。

另请注意,函数调用不仅仅是fn-expr后跟() ,而且expression式列表通常在括号内(包括一个空列表)。 之间有一个很大的区别:

 for i := range whatever { defer func() { fmt. Println(i) }() } 

 for i := range whatever { defer func(n int) { fmt. Println(n) }(i) } 

第一个版本在执行闭包的同时打印“i”的值,第二个版本在执行延迟语句的瞬间打印“i”的值。

参考

Go编程语言规范

函数types

函数types表示具有相同参数和结果types的所有函数的集合。

 FunctionType = "func" Signature . Signature = Parameters [ Result ] . Result = Parameters | Type . Parameters = "(" [ ParameterList [ "," ] ] ")" . ParameterList = ParameterDecl { "," ParameterDecl } . ParameterDecl = [ IdentifierList ] [ "..." ] Type . 

函数声明

函数声明将标识符(函数名称)绑定到函数。

 FunctionDecl = "func" FunctionName Signature [ Body ] . FunctionName = identifier . Body = Block . 

函数文字

函数文字表示一个匿名函数。 它由函数types和函数体的规范组成。

 FunctionLit = FunctionType Body . 

函数文字是闭包:它们可能引用周围函数中定义的variables。 然后这些variables在周围的函数和函数文字之间被共享,并且只要它们是可访问的,它们就存活下来。

一个函数literal可以被分配给一个variables或直接调用。

呼叫

给定函数typesF的expression式f

 f(a1, a2, … an) 

用参数a1, a2, … an调用f

在函数调用中,函数值和参数按通常的顺序进行评估。 在它们被评估之后,调用的参数被传递给函数,并且被调用的函数开始执行。 当函数返回时,函数的返回参数被传递给调用函数。

延迟陈述

defer ”语句调用执行延迟到周围函数返回时的函数。

 DeferStmt = "defer" Expression . 

expression式必须是函数或方法调用。 每次执行“ defer ”语句时,调用的函数值和参数将照常进行计算并重新保存,但实际函数不会被调用。 相反,延迟调用紧接在周围函数返回之前,返回值(如果有的话)已经被评估之后,但在它们被返回给调用者之前,以LIFO顺序执行。

既然你还是感到困惑,这里是另一个试图提供你的问题的答案。

在你的问题的上下文中, ()是函数调用操作符。

例如,函数文字

 func(i int) int { return 42 * i } 

代表一个匿名function。

()函数调用操作符之后的函数literal

 func(i int) int { return 42 * i }(7) 

代表一个直接被调用的匿名函数。

通常,在函数调用中,函数值和参数按通常的顺序进行评估。 在它们被评估之后,调用的参数被传递给函数,并且被调用的函数开始执行。 当函数返回时,函数的返回参数被传递给调用函数。

但是,通过延迟语句调用函数是一个特例。 每次执行“延迟”语句时,调用的函数值和参数将照常进行计算并重新保存,但实际函数不会被调用。 相反,延迟调用紧接在周围函数返回之前,返回值(如果有的话)已经被评估之后,但在它们被返回给调用者之前,以LIFO顺序执行。

defer语句expression式必须是直接调用的函数或方法调用,而不是直接调用的函数或方法文字。 因此,函数或方法字面量需要由()函数调用操作符跟随,以便延迟语句expression式是函数或方法调用。

推迟声明

 defer func(i int) int { return 42 * i }(7) 

已validation。

推迟声明

 defer func(i int) int { return 42 * i } 

无效: syntax error: argument to go/defer must be function call