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