2016-12-03 1 views
6

Ich schreibe einen Parser in Go for Go, und um es zu testen, habe ich eine Reihe von Dateien aus GitHub-Projekten heruntergeladen.
In https://github.com/andlabs/ui stieß ich auf eine Datei dieses Stück Code enthält:Sind unbenannte Argumente ein Ding in Go?

func moveLabel(*Button) { 
    from := movingCurrent 
    to := 0 
    if from == 0 { 
     to = 1 
    } 
    movingBoxes[from].Delete(0) 
    movingBoxes[to].Append(movingLabel, false) 
    movingCurrent = to 
} 

Es verwirrt mir ein bisschen einen Zeiger auf ein Button ohne einen Namen als Funktion Argument, um zu sehen, die von innen unmöglich zu Referenz machen die Funktion.
Es scheint jedoch syntaktisch korrekt zu sein, da der Compiler nicht klagt.
Was ist der Zweck der Argumente ungezähmter Funktionen in Go?

+0

Hinzugefügt mehr Details, Erklärung (basierend auf der Spezifikation) und Links zur Antwort. – icza

Antwort

8

Unbenannte Parameter sind einwandfrei gültig. Die Parameter declaration aus der Spezifikation:

ParameterDecl = [ IdentifierList ] [ "..." ] Type . 

Wie Sie sehen können, die IdentifierList (die Kennung oder die Namen) sind in eckigen Klammern gesetzt, was bedeutet, es ist optional. Nur die Type ist erforderlich.

Der Grund dafür ist, dass die Namen für jemanden, der eine Methode oder Funktion aufruft, nicht wirklich wichtig sind. Was zählt, sind die Arten der Parameter und ihre Reihenfolge. Dies wird in dieser Antwort ausführlich beschrieben: Getting method parameter names in Golang

Im Allgemeinen benennen Sie Variablen und Parameter, so dass Sie auf sie verweisen können.

Wenn Sie etwas nicht nennen, liegt es daran, dass Sie nicht darauf verweisen möchten.

Also sollte die Frage eher lauten: Warum würde ich nicht auf einen Parameter verweisen wollen?

Zum Beispiel, weil der Parameter „gibt es“ (es wird übergeben), aber Sie brauchen nicht es, Sie nicht wollen, es zu benutzen. Warum sollte es da sein, wenn ich es nicht brauche?

Da jemand oder etwas diktiert für bestimmte Parameter, um dort zu sein. Sie möchten z. B. eine Schnittstelle implementieren oder einen Funktionswert übergeben, dessen Signatur durch den erwarteten Funktionstyp definiert ist.

Lassen Sie uns ein Beispiel sehen. Wir haben folgende MyWriter Schnittstelle:

type MyWriter interface { 
    Write(p []byte) error 
} 

A io.Writer vereinfacht, die nur einen Fehler zurückgibt, sondern berichten nicht die Anzahl der geschriebenen Bytes. Wenn Sie eine Implementierung zur Verfügung zu stellen würde wollen, die nur die Daten (ähnlich ioutil.Discard) verwirft, dann wird die Umsetzung nicht verwendet werden (muss nicht verwenden) sein Argument:

type DiscardWriter struct{} 

func (DiscardWriter) Write([]byte) error { return nil } 

und das ist alles: wir don‘ t benutzen Sie den Empfänger, wir verwenden das Argument nicht. Beide können ungenannt sein. Und die Implementierung macht genau das, was sie sollte.

Tun Sie dies (mit unbenannten Parametern) auch Dokumente, dass der Wert nicht verwendet/bezogen wird.

Ein weiterer Grund kann vorwärts Kompatibilität sein. Wenn Sie eine Bibliothek freigeben, können Sie die Parameterliste nicht ändern oder erweitern, ohne die Abwärtskompatibilität zu beeinträchtigen (und in Go gibt es keine Funktionsüberladung: Wenn Sie zwei Varianten mit unterschiedlichen Parametern haben möchten, müssen deren Namen ebenfalls unterschiedlich sein). Sie können also eine exportierte Funktion oder Methode mit zusätzlichen Parametern frühzeitig deklarieren, aber da Sie sie noch nicht verwenden, können Sie sie unbenannt lassen. Ein Beispiel hierfür ist in dieser Antwort ausführlich beschrieben: Why does Go allow compilation of unused function parameters?

Eine Sache zu beachten ist hier, dass Sie benannte und unbenannte Parameter nicht mischen können. Wenn Sie einige benennen, müssen Sie alle benennen. Wenn Sie nicht alle benötigen, können Sie die blank identifier wie in diesem Beispiel verwenden:

Ein einfacher Web-Server, die mit dem "Hello" Text auf alle Anfragen reagiert:

http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { 
    io.WriteString(w, "Hello") 
}) 
panic(http.ListenAndServe(":8080", nil)) 

Die Funktion Handler Senden die "Hello" zurück Text verwendet nur den Antwortschreiber w, aber nicht die Anfragestruktur, daher wird der leere Bezeichner als Name verwendet.

Eine weitere damit verbundene Frage:

Why must we declare a variable name when adding a method to a struct in Golang?

auch etwas verwandte, aber bezüglich der Verwendung von/Benennung zurückgegebenen Werte:

Return map like 'ok' in Golang on normal functions