Sintassi della dichiarazione di funzione: elementi tra parentesi prima del nome della funzione


250

Mi dispiace non poter essere più specifico nel titolo della domanda, ma stavo leggendo del codice Go e ho riscontrato dichiarazioni di funzioni di questo modulo:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ...
}

da https://github.com/mattermost/platform/blob/master/api/context.go

func (s *GracefulServer) BlockingClose() bool {
    ...
}

da https://github.com/braintree/manners/blob/master/server.go

Cosa fa il (h handler)e (s *GracefulServer)tra parentesi media? Cosa significa l'intera dichiarazione di funzione, tenendo conto del significato delle cose tra parentesi?

modificare

Questo non è un duplicato di Qual è la differenza di funzioni e metodi in Go? : questa domanda mi è venuta in mente perché non sapevo quali fossero le cose tra parentesi prima del nome della funzione, non perché mi chiedevo quale fosse la differenza tra funzioni e metodi ... se sapessi che questa dichiarazione era un metodo non vorrei Non ho avuto questa domanda in primo luogo. Se qualcuno ha gli stessi dubbi di me un giorno, non credo che andrà alla ricerca di "metodi golang" perché non sa che è così. Sarebbe come chiedersi cosa significhi la lettera "sigma" prima di un'espressione matematica (non sapere che significa sommatoria) e qualcuno dice che è un duplicato di qual è la differenza tra sommatoria e qualche altra cosa.

Inoltre, la risposta breve a questa domanda ("è un ricevitore") non è una risposta a "qual è la differenza tra funzioni e metodi".


27
@Volker quindi mette un disclaimer che dice che le persone di Go su StackOverflow rispondono solo a domande che non sono nel Tour of Go. Nella comunità di Haskell, le persone possono porre domande come Come posso ottenere nl'elemento dall'elenco in Haskell? , che è nell'Introduzione su Impara te a Haskell per il Grande Bene e ottenere risposte alle loro domande senza fare storie.
Marcus Vinícius Monteiro,

23
Quando ho avuto questa domanda, sono andato per la prima volta al Go Tour. Ho controllato tutti i titoli "Funzione" e nessuno degli esempi ha coperto questo. tour.golang.org/basics/4 tour.golang.org/basics/5 Se non sai di espandere Metodi e interfacce, non vedrai il titolo "I metodi sono funzioni". Questa domanda è valida e ottima per l'indicizzazione di Google. I fanatici duplicati della bandiera devono alleggerire.
Bruno Bronosky,

14
Grazie per non essere specifico nella tua domanda, perché è stato abbastanza per aiutarmi a trovare la risposta!
David K,

1
Hai chiesto esattamente cosa cercavo, è una domanda valida. Grazie. Ho letto tutti i tipi di definizione delle funzioni e nessuno l'ha spiegato. Ho ancora provato a scrivere la mia domanda nuvola e ho trovato questo.
Ajak6,

Risposte:


200

Questo si chiama "ricevitore". Nel primo caso (h handler)è un tipo di valore, nel secondo (s *GracefulServer)è un puntatore. Il modo in cui funziona in Go può variare leggermente rispetto ad altre lingue. Tuttavia, il tipo di ricezione funziona più o meno come una classe nella maggior parte della programmazione orientata agli oggetti. È la cosa da cui chiami il metodo, proprio come se mettessi un metodo Aa parte una classe Personquindi avrei bisogno di un'istanza di tipo Personper chiamare A(supponendo che sia un metodo di istanza e non statico!).

Una Gotcha qui è che il ricevitore viene inserito nello stack delle chiamate come gli altri argomenti per cui se il ricevitore è un tipo di valore, come nel caso di handlerallora si dovrà lavorare su una copia della cosa che si chiama il metodo da che significa qualcosa come h.Name = "Evan"Would non persistono dopo il ritorno all'ambito chiamante. Per questo motivo tutto ciò che si aspetta di cambiare lo stato del ricevitore, deve usare un puntatore o restituire il valore modificato (dà più di un paradigma di tipo immutabile se lo stai cercando).

Ecco la sezione pertinente dalle specifiche; https://golang.org/ref/spec#Method_sets


6
Buona spiegazione e ulteriori punti karma per il collegamento alle specifiche pertinenti
Marius Waldal,

4
Il tour di Golang ha anche alcuni esempi piuttosto utili tour.golang.org/methods/1
tw_hoff

90

Significa che ServeHTTPnon è una funzione autonoma. La parentesi prima del nome della funzione è il modo Go di definire l'oggetto su cui queste funzioni opereranno. Quindi, essenzialmente ServeHTTPè un metodo del gestore del tipo e può essere invocato usando qualsiasi oggetto, diciamo h, del gestore del tipo.

h.ServeHTTP(w, r)

Sono anche chiamati ricevitori. Esistono due modi per definirli. Se vuoi modificare il ricevitore usa un puntatore come:

func (s *MyStruct) pointerMethod() { } // method on pointer

Se non è necessario modificare il ricevitore, è possibile definire il ricevitore come un valore come:

func (s MyStruct)  valueMethod()   { } // method on value

Questo esempio di Go playground dimostra il concetto.

package main

import "fmt"

type Mutatable struct {
    a int
    b int
}

func (m Mutatable) StayTheSame() {
    m.a = 5
    m.b = 7
}

func (m *Mutatable) Mutate() {
    m.a = 5
    m.b = 7
}

func main() {
    m := &Mutatable{0, 0}
    fmt.Println(m)
    m.StayTheSame()
    fmt.Println(m)
    m.Mutate()
    fmt.Println(m)

L'output del programma sopra è:

&{0 0}
&{0 0}
&{5 7}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.