为什么在 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

}

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



凤凰求蛊
浏览 374回答 4
4回答

开满天机

这并不是说()必须(仅)一个后添加封在defer。defer 语句的语言规范要求其“表达式”始终必须是函数调用。为什么会这样?它与任何其他函数相同,无论是否“延迟”:考虑:func f() int { return 42 }和a := f对比b := f()第一个表达式 RHS 是一个函数值。在第二个版本中,RHS 是函数返回的值——即函数调用。语义也是如此:defer f对比defer f()除了第一个版本在“延迟”的上下文中没有意义,因此规范提到它必须是第二种形式(仅)。恕我直言,由于与“延迟”语句之外的上述函数调用的正交性,因此也更容易学习。另请注意,函数调用不仅是 fn-expr 后跟(),而且表达式列表通常位于括号内(包括空列表)。之间有很大的区别:for i := range whatever {&nbsp; &nbsp; &nbsp; &nbsp; defer func() { fmt. Println(i) }()}和for i := range whatever {&nbsp; &nbsp; &nbsp; &nbsp; defer func(n int) { fmt. Println(n) }(i)}关闭时,第一个版本在当下打印的“我”的值执行,第二打印“我”在当下的价值时,defer语句被执行。

杨__羊羊

参考Go 编程语言规范函数类型函数类型表示具有相同参数和结果类型的所有函数的集合。FunctionType&nbsp;&nbsp;&nbsp;=&nbsp;"func"&nbsp;Signature&nbsp;.Signature&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;Parameters&nbsp;[&nbsp;Result&nbsp;]&nbsp;.Result&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;Parameters&nbsp;|&nbsp;Type&nbsp;.Parameters&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;"("&nbsp;[&nbsp;ParameterList&nbsp;[&nbsp;","&nbsp;]&nbsp;]&nbsp;")"&nbsp;.ParameterList&nbsp;&nbsp;=&nbsp;ParameterDecl&nbsp;{&nbsp;","&nbsp;ParameterDecl&nbsp;}&nbsp;.ParameterDecl&nbsp;&nbsp;=&nbsp;[&nbsp;IdentifierList&nbsp;]&nbsp;[&nbsp;"..."&nbsp;]&nbsp;Type&nbsp;.函数声明函数声明将标识符(函数名称)绑定到函数。FunctionDecl&nbsp;=&nbsp;"func"&nbsp;FunctionName&nbsp;Signature&nbsp;[&nbsp;Body&nbsp;]&nbsp;.FunctionName&nbsp;=&nbsp;identifier&nbsp;.Body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;Block&nbsp;.函数字面量函数文字表示匿名函数。它由函数类型的规范和函数体组成。FunctionLit&nbsp;=&nbsp;FunctionType&nbsp;Body&nbsp;.函数字面量是闭包:它们可以引用在周围函数中定义的变量。然后这些变量在周围的函数和函数字面量之间共享,只要它们可访问,它们就会存在。函数文字可以分配给变量或直接调用。通话给定一个f函数类型的表达式F,f(a1,&nbsp;a2,&nbsp;…&nbsp;an)f带参数的调用a1, a2, … an。在函数调用中,函数值和参数按通常的顺序计算。在对它们求值后,调用的参数按值传递给函数,被调用的函数开始执行。当函数返回时,函数的返回参数按值传递回调用函数。推迟声明"&nbsp;defer" 语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻。DeferStmt&nbsp;=&nbsp;"defer"&nbsp;Expression&nbsp;.表达式必须是函数或方法调用。每次“&nbsp;defer”语句执行时,函数值和调用的参数都会像往常一样被评估并重新保存,但不会调用实际的函数。相反,延迟调用在周围函数返回之前立即以 LIFO 顺序执行,在返回值(如果有)被评估之后,但在它们返回给调用者之前。由于您仍然感到困惑,这是为您的问题提供答案的另一种尝试。在您的问题的上下文中,()是函数调用运算符。例如,函数字面量func(i&nbsp;int)&nbsp;int&nbsp;{&nbsp;return&nbsp;42&nbsp;*&nbsp;i&nbsp;}表示匿名函数。函数文字后跟()函数调用运算符func(i&nbsp;int)&nbsp;int&nbsp;{&nbsp;return&nbsp;42&nbsp;*&nbsp;i&nbsp;}(7)表示一个匿名函数,然后直接调用该函数。通常,在函数调用中,函数值和参数按通常的顺序计算。在对它们求值后,调用的参数按值传递给函数,被调用的函数开始执行。当函数返回时,函数的返回参数按值传递回调用函数。但是,通过 defer 语句调用函数是一种特殊情况。每次执行“defer”语句时,函数值和调用的参数都会像往常一样评估并重新保存,但不会调用实际的函数。相反,延迟调用在周围函数返回之前立即以 LIFO 顺序执行,在返回值(如果有)被评估之后,但在它们返回给调用者之前。defer 语句表达式必须是直接调用的函数或方法调用,而不仅仅是未直接调用的函数或方法文字。因此,函数或方法字面量后面需要跟()函数调用运算符,这样 defer 语句表达式就是函数或方法调用。延迟声明defer&nbsp;func(i&nbsp;int)&nbsp;int&nbsp;{&nbsp;return&nbsp;42&nbsp;*&nbsp;i&nbsp;}(7)已验证。延迟声明defer&nbsp;func(i&nbsp;int)&nbsp;int&nbsp;{&nbsp;return&nbsp;42&nbsp;*&nbsp;i&nbsp;}无效:syntax error: argument to go/defer must be function call。

慕虎7371278

如果没有 (),您就不会执行该函数。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go