2013-04-15 7 views
36

lese ich The Go Programming Language Specifications und fand mich mit nicht wirklich verstehen "()" nach dem Verschlusskörper:Warum hinzufügen "()" nach Verschluss Körper in Golang?

In Function literals:

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

In Defer statements‚s Beispiel:

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

Ich bin nicht über den Grund klar, & Verwendung von "()" nach Verschluss Körper hinzuzufügen, hoffe jemand kann dies deutlich zu erklären.

Antwort

54

Es ist nicht erforderlich, dass () nach (nur) einem Verschluss in defer hinzugefügt werden muss. Die Sprachspezifikationen für das defer statement Mandat, dass sein "Ausdruck" immer muss ein Funktionsaufruf sein.

Und warum ist es so? Es ist das gleiche wie bei jeder anderen Funktion, in 'defer' oder nicht:

Bedenken Sie:

func f() int { return 42 } 

und

a := f 

vs

b := f() 

Der erste Ausdruck RHS ist ein Funktionswert. In der zweiten Version ist der RHS der Wert , der von der Funktion - d.h. einem Funktionsaufruf - zurückgegeben wird.

So ist die Semantik:

defer f 

vs

defer f() 

der Ausnahme, dass die erste Version nicht sinnvoll im Zusammenhang mit dem 'defer' machen, und so erwähnen die Spezifikationen, dass es muss die zweite Form sein (nur).

Es ist IMHO auch leichter zu lernen wegen der Orthogonalität mit dem oben genannten Funktionsaufruf außerhalb der 'Defer' Anweisung.

Beachten Sie auch, dass ein Funktionsaufruf nicht nur Fn-Ausdruck gefolgt von () ist, aber eine Ausdrucksliste ist in der Regel innerhalb der Klammer (einschließlich einer leeren Liste). Es gibt einen großen Unterschied zwischen:

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

und

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

Die erste Version gibt den Wert von ‚i‘ in dem Moment, wenn der Verschluss ausführt, druckt der zweite den Wert von ‚i‘ in dem Moment, als die Defer-Anweisung ausgeführt wurde.

+1

bekam ich Ihren Punkt, so in 'func (ch chan int) {ch <- ACK} (replyChan)', 'func (ch chan int) {ch <- ACK}' bedeutet die Definition der Schließung, '(replyChan) 'bedeutet" führe diese Schließung mit dem Parameter 'replyChan'" aus. –

+0

Noch eine Frage zu Ihrem letzten Beispiel: Was ist der Unterschied zwischen 'in dem Moment, in dem die Schließung durchgeführt wird 'und' in dem Moment, als die Defer-Anweisung ausgeführt wurde? Wenn ich nach 'for {}' '' return '' habe, sollten beide 2 'Defer's gleichzeitig vor' return' ausgeführt werden, oder? –

+0

@ReckHou: Run http://play.golang.org/p/Orm-0EaBY6 und schauen Sie sich die Ausgabe – zzzz

13

Referenzen

The Go Programming Language Specification

Function types

A Funktionsart die Menge aller Funktionen mit den gleichen Parameter und Ergebnistypen bezeichnet.

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

Function declarations

A bindet Funktionsdeklaration einen Identifikator, den Namen der Funktion, auf ein Funktion.

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

Function literals

A Funktionsliteral stellt eine anonyme Funktion. Es besteht aus einer Spezifikation des Funktionstyps und eines Funktionskörpers.

FunctionLit = FunctionType Body . 

Funktionsliterale sind Schließungen: sie Variablen in eine umgebende Funktion definiert beziehen. Diese Variablen werden dann zwischen der Umgebungsfunktion und dem Funktionsliteral gemeinsam genutzt, und sie bleiben als erhalten, solange sie zugänglich sind.

Ein Funktionsliteral kann einer Variablen zugewiesen oder direkt aufgerufen werden.

Calls

F, ein Ausdruck f von Funktionstyp Gegeben

f(a1, a2, … an) 

Anrufe f mit Argumenten a1, a2, … an.

In einem Funktionsaufruf werden der Funktionswert und die Argumente in der üblichen Reihenfolge ausgewertet. Nach der Auswertung werden die Parameter des Aufrufs als Wert an die Funktion übergeben und die aufgerufene Funktion beginnt mit der Ausführung . Die Rückgabe-Parameter der Funktion werden mit dem Wert an die aufrufende Funktion zurückgegeben, wenn die Funktion zurückkehrt.

Defer statements

A "defer" Anweisung ruft eine Funktion, deren Ausführung bis zu dem Moment aufgeschoben wird, um die umgebende Funktion zurückkehrt.

DeferStmt = "defer" Expression . 

Der Ausdruck muss ein Funktions- oder Methodenaufruf sein. Jedes Mal, wenn die Anweisung "defer" ausgeführt wird, werden der Funktionswert und die Parameter für den Aufruf wie üblich ausgewertet und erneut gespeichert, aber die aktuelle Funktion wird nicht aufgerufen.Stattdessen werden zurückgestellte Aufrufe in der LIFO-Reihenfolge ausgeführt, unmittelbar bevor die Umgebungsfunktion zurückkehrt, nachdem die zurückgegebenen Werte , falls vorhanden, ausgewertet wurden, bevor sie jedoch an den Aufrufer zurückgegeben werden.

Da Sie immer noch verwirrt sind, hier ein weiterer Versuch, eine Antwort auf Ihre Frage zu geben.

Im Kontext Ihrer Frage ist () der Funktionsaufruf-Operator.

Zum Beispiel die Funktionsliteral

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

stellt eine anonyme Funktion.

Die Funktionsliteral durch die

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

eine anonyme Funktion repräsentiert

Operator () Funktionsaufruf folgt, die dann direkt aufgerufen wird.

Normalerweise werden in einem Funktionsaufruf der Funktionswert und die Argumente in der üblichen Reihenfolge ausgewertet. Nach der Auswertung werden die Parameter des Aufrufs als Wert an die Funktion übergeben und die aufgerufene Funktion beginnt mit der Ausführung. Die Rückgabeparameter der Funktion werden bei Rückgabe der Funktion durch Wert an die aufrufende Funktion zurückgegeben.

Das Aufrufen der Funktion durch die Defer-Anweisung ist jedoch ein Sonderfall. Jedes Mal, wenn die "Defer" -Anweisung ausgeführt wird, werden der Funktionswert und die Parameter für den Aufruf wie üblich ausgewertet und erneut gespeichert, aber die eigentliche Funktion wird nicht aufgerufen. Stattdessen werden verzögerte Aufrufe in LIFO-Reihenfolge ausgeführt, unmittelbar bevor die umgebende Funktion zurückkehrt, nachdem die Rückgabewerte, falls vorhanden, ausgewertet wurden, aber bevor sie an den Aufrufer zurückgegeben werden.

Der Ausdruck der Defer-Anweisung muss ein Funktions- oder Methodenaufruf sein, der direkt aufgerufen wird, nicht nur ein Funktions- oder Methodenliteral, das nicht direkt aufgerufen wird. Daher muss dem Funktions- oder Methodenliteral der Funktionsaufrufoperator () folgen, damit der Ausdruck der Defer-Anweisung ein Funktions- oder Methodenaufruf ist.

Die Zurückstellungs Anweisung

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

gültig ist.

Die Zurückstellungs Anweisung

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

ist ungültig: syntax error: argument to go/defer must be function call.

Verwandte Themen