我正在阅读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
}
我不清楚添加&的原因封闭体后使用“()”,希望有人能清楚地解释清楚。
答案 0 :(得分:62)
()
中的{em>闭包后,defer
必须添加func f() int { return 42 }
。 defer statement要求其“表达式”始终的语言规范必须是函数调用。
为什么会这样?它与任何其他功能相同,无论是否“延迟”:
考虑:
a := f
和
b := f()
VS
defer f
第一个表达式RHS是一个函数值。在第二个版本中,RHS是函数返回的值 - 即函数调用。
语义也是如此:
defer f()
VS
()
除了第一个版本在'defer'的上下文中没有意义,因此规范提到它必须是第二个形式(仅)。
由于上面讨论的函数调用在'defer'语句之外的正交性,因此恕我直言也更容易学习。
另请注意,函数调用不仅是fn-expr后跟for i := range whatever {
defer func() { fmt. Println(i) }()
}
,而且表达式列表通常位于括号内(包括空列表)。之间有很大的不同:
for i := range whatever {
defer func(n int) { fmt. Println(n) }(i)
}
和
{{1}}
第一个版本在闭包执行时打印'i'的值,第二个版本在defer语句 时打印'i'的值em>执行。
答案 1 :(得分:14)
参考
The Go Programming Language Specification
函数类型表示具有相同功能的所有函数的集合 参数和结果类型。
FunctionType = "func" Signature . Signature = Parameters [ Result ] . Result = Parameters | Type . Parameters = "(" [ ParameterList [ "," ] ] ")" . ParameterList = ParameterDecl { "," ParameterDecl } . ParameterDecl = [ IdentifierList ] [ "..." ] Type .
函数声明将标识符(函数名称)绑定到a 功能
FunctionDecl = "func" FunctionName Signature [ Body ] . FunctionName = identifier . Body = Block .
函数文字表示匿名函数。它由一个 函数类型和函数体的规范。
FunctionLit = FunctionType Body .
函数文字是闭包:它们可以引用在中定义的变量 周围的功能。然后在这些变量之间共享这些变量 周围函数和函数文字,它们存活下来 只要他们可以访问。
可以将函数文本分配给变量或直接调用。
给定函数类型
f
的表达式F
,f(a1, a2, … an)
使用参数
f
调用a1, a2, … an
。在函数调用中,将计算函数值和参数 通常的顺序。在评估它们之后,调用的参数 通过值传递给函数,并且被调用的函数开始 执行。函数的返回参数按值传递 函数返回时返回调用函数。
“
defer
”语句调用其执行延迟的函数 到周围的函数返回的那一刻。DeferStmt = "defer" Expression .
表达式必须是函数或方法调用。每一次 “
defer
”语句执行,函数值和参数 呼叫按常规进行评估并重新保存,但实际功能是 没有被调用。相反,延迟调用以LIFO顺序执行 在周围函数返回之前,返回之后 值(如果有)已经过评估,但在它们返回之前 来电者。
由于您仍然感到困惑,这是另一种尝试来回答您的问题。
在您的问题的上下文中,()
是函数调用运算符。
例如,函数文字
func(i int) int { return 42 * i }
表示匿名函数。
函数文字后跟()
函数调用操作符
func(i int) int { return 42 * i }(7)
表示一个匿名函数,然后直接调用。
通常,在函数调用中,函数值和参数按通常顺序计算。在评估它们之后,调用的参数通过值传递给函数,并且被调用的函数开始执行。当函数返回时,函数的返回参数通过值传递回调用函数。
但是,通过defer语句调用该函数是一种特殊情况。每次执行“defer”语句时,将像往常一样评估调用的函数值和参数,并重新保存但不调用实际函数。相反,延迟调用在周围函数返回之前立即以LIFO顺序执行,在返回值(如果有)已经评估之后,但在它们返回给调用者之前。
defer语句表达式必须是直接调用的函数或方法调用,而不仅仅是不直接调用的函数或方法文字。因此,函数或方法文字需要由()
函数调用操作符跟随,以便defer语句表达式是函数或方法调用。
延期陈述
defer func(i int) int { return 42 * i }(7)
有效。
延期陈述
defer func(i int) int { return 42 * i }
无效:syntax error: argument to go/defer must be function call
。
答案 2 :(得分:0)
如果您不想阅读冗长的答案:
str := "Alice"
go func(name string) {
fmt.Println("Your name is", name)
}(str)
与:
str := "Alice"
f := func(name string) {
fmt.Println("Your name is", name)
}
go f(str)
答案 3 :(得分:0)
没有(),您没有执行该函数。