53

私は読ん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
}

クロージャー本体の後に「()」を追加して使用する理由がよくわかりません。誰かがこれを明確に説明してくれることを願っています。

4

4 に答える 4

75

のクロージャー()後に (のみ) 追加する必要があるわけではありません。defer ステートメントの言語仕様は、その「式」が常に関数呼び出しでなければならないことを義務付けています。defer

そして、それはなぜですか?「延期」するかどうかに関係なく、他の関数と同じです。

検討:

func f() int { return 42 }

a := f

b := f()

最初の式 RHS は関数値です。2 番目のバージョンでは、RHS は関数 (関数呼び出し)によって返される値です。

次のセマンティクスも同様です。

defer f

defer f()

ただし、最初のバージョンは「延期」のコンテキストでは意味をなさないため、仕様では、2 番目の形式 (のみ) でなければならないと述べています。

「defer」ステートメントの外側で上記の関数呼び出しと直交しているため、私見も学習が容易です。

()また、関数呼び出しは fn-expr の後に が続くだけでなく、通常、式リストは括弧内にあることに注意してください(空のリストを含む)。次の点に大きな違いがあります。

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

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

最初のバージョンは、クロージャが実行された瞬間の「i」の値を出力し、2 番目のバージョンは、defer ステートメント実行された瞬間の「i」の値を出力します。

于 2013-04-15T06:17:43.520 に答える