Syntaxe de déclaration de fonction: éléments entre parenthèses avant le nom de la fonction

250

Je suis désolé de ne pas avoir pu être plus précis dans le titre de la question, mais je lisais du code Go et j'ai rencontré des déclarations de fonction de ce formulaire:

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

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

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

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

Qu'est - ce que la (h handler)et (s *GracefulServer)entre parenthèses moyenne? Que signifie toute la déclaration de fonction, compte tenu de la signification des choses entre parenthèses?

Éditer

Ce n'est pas un doublon de Quelle est la différence de fonctions et de méthodes dans Go? : cette question m'est venue parce que je ne savais pas ce qu'il y avait entre parenthèses avant le nom de la fonction, pas parce que je me demandais quelle était la différence entre les fonctions et les méthodes ... si je savais que cette déclaration était une méthode que je ne ferais pas '' t ont eu cette question en premier lieu. Si quelqu'un a un jour le même doute que moi, je ne crois pas qu'elle ira chercher des "méthodes de golang" car elle ne sait pas que c'est le cas. Ce serait comme se demander ce que la lettre «sigma» signifie avant une expression mathématique (ne pas savoir qu'elle signifie sommation) et quelqu'un dit que c'est un doublon de ce qui fait la différence entre la sommation et une autre chose.

De plus, la réponse courte à cette question ("c'est un récepteur") n'est pas une réponse à "quelle est la différence entre les fonctions et les méthodes".

Marcus Vinícius Monteiro
la source
27
@Volker a ensuite mis un avertissement disant que les gens de Go sur stackoverflow ne répondent qu'aux questions qui ne sont pas sur le Tour de Go. Dans la communauté de Haskell, les gens peuvent poser des questions comme Comment puis-je obtenir l' nélément de la liste dans Haskell? , qui se trouve dans l'introduction sur Learn you a Haskell for Great Good et obtenez des réponses à leurs questions sans faire d'histoires à ce sujet.
Marcus Vinícius Monteiro
23
Quand j'ai eu cette question, je suis d'abord allé au Go Tour. J'ai vérifié tous les titres de "Fonction" et aucun des exemples ne l'a couvert. tour.golang.org/basics/4 tour.golang.org/basics/5 Si vous ne savez pas développer les méthodes et les interfaces, vous ne verrez pas le titre "Les méthodes sont des fonctions". Cette question est valable et idéale pour l'indexation de Google. Les fanatiques de drapeau en double doivent s'éclaircir.
Bruno Bronosky
14
Merci de ne pas être précis dans votre question, car cela a suffi pour m'aider à trouver la réponse!
David K
1
Vous avez demandé exactement ce que je cherchais, c'est une question valide. Je vous remercie. J'ai lu toutes sortes de définitions de fonctions et personne ne l'a expliqué. J'ai toujours essayé d'écrire ma question nube et j'ai trouvé cela.
Ajak6

Réponses:

200

C'est ce qu'on appelle le «récepteur». Dans le premier cas, (h handler)il s'agit d'un type de valeur, dans le second, (s *GracefulServer)il s'agit d'un pointeur. La façon dont cela fonctionne dans Go peut varier un peu de certaines autres langues. Cependant, le type de réception fonctionne plus ou moins comme une classe dans la plupart des programmes orientés objet. C'est la chose à partir de laquelle vous appelez la méthode, un peu comme si je mettais une méthode Adans une classe, Personalors j'aurais besoin d'une instance de type Personpour appeler A(en supposant que c'est une méthode d'instance et non statique!).

Un problème ici est que le récepteur est poussé sur la pile d'appels comme les autres arguments, donc si le récepteur est un type de valeur, comme dans le cas, handlervous travaillerez sur une copie de ce que vous avez appelé la méthode à partir de ce qui signifierait quelque chose comme le h.Name = "Evan"ferait ne persiste pas après que vous revenez à la portée d'appel. Pour cette raison, tout ce qui s'attend à changer l'état du récepteur, doit utiliser un pointeur ou retourner la valeur modifiée (donne plus d'un paradigme de type immuable si vous le recherchez).

Voici la section pertinente de la spécification; https://golang.org/ref/spec#Method_sets

evanmcdonnal
la source
6
Bonne explication et points de karma supplémentaires pour le lien vers les spécifications pertinentes
Marius Waldal
4
La tournée de golang a aussi des exemples assez utiles tour.golang.org/methods/1
tw_hoff
91

Cela signifie que ce ServeHTTPn'est pas une fonction autonome. La parenthèse devant le nom de la fonction est le moyen Go de définir l'objet sur lequel ces fonctions vont opérer. Donc, c'est essentiellement ServeHTTPune méthode de type handler et peut être invoquée en utilisant n'importe quel objet, disons h, de type handler.

h.ServeHTTP(w, r)

Ils sont également appelés récepteurs. Il existe deux façons de les définir. Si vous souhaitez modifier le récepteur, utilisez un pointeur comme:

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

Si vous n'avez pas besoin de modifier le récepteur, vous pouvez définir le récepteur comme une valeur comme:

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

Cet exemple de Go Playground illustre le concept.

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)

Le résultat du programme ci-dessus est:

&{0 0}
&{0 0}
&{5 7}
Abhishek Nalin
la source