web-dev-qa-db-fra.com

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

Je suis désolé, je ne pourrais pas ê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 cette forme:

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

à partir de https://github.com/mattermost/platform/blob/master/api/context.go

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

à partir de https://github.com/braintree/manners/blob/master/server.go

Que signifient (h handler) et (s *GracefulServer) entre parenthèses? Qu'est-ce que la déclaration de fonction entière signifie, en tenant compte du sens des choses entre parenthèses?

Modifier

Ce n'est pas une copie 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 que les choses étaient 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, je n'aurais pas eu cette question au départ. Si quelqu'un a le même doute que moi un jour, je ne crois pas qu'elle ira à la recherche de "méthodes 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 sachant pas que cela signifie sommation) et quelqu'un dit que c'est une copie de ce qui est la différence entre 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".

179

Ceci est appelé le "récepteur". Dans le premier cas (h handler) c'est un type de valeur, dans le second (s *GracefulServer) c'est un pointeur. La façon dont cela fonctionne dans Go peut varier un peu de certaines autres langues. Toutefois, le type de réception fonctionne plus ou moins comme une classe dans la plupart des programmes orientés objet. C’est la chose dont vous appelez la méthode, un peu comme si je mettais une méthode A à côté d’une classe Person alors j’aurais besoin d’une instance de type Person pour pouvoir appeler A (en supposant que c'est une méthode d'instance et non statique!).

On comprend que le destinataire est poussé sur la pile d'appels comme les autres arguments. Par conséquent, si le destinataire est un type de valeur, comme dans le cas de handler, vous travaillerez sur une copie de ce que vous avez appelé la méthode. signifiant quelque chose comme h.Name = "Evan" ne persisterait pas après le retour à l'étendue de l'appel. Pour cette raison, tout ce qui devrait changer l’état du récepteur, doit utiliser un pointeur ou renvoyer la valeur modifiée (donne plus d’un paradigme de type immuable si vous recherchez cela).

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

153
evanmcdonnal

Cela signifie que ServeHTTP n'est pas une fonction autonome. La parenthèse précédant le nom de la fonction est le moyen de définir l’objet sur lequel ces fonctions seront exécutées. Donc, essentiellement ServeHTTP est une méthode de gestionnaire de types et peut être appelée à l'aide de n'importe quel objet, disons h, de gestionnaire de types.

h.ServeHTTP(w, r)

Ils sont aussi appelés récepteurs. Il y a deux façons de les définir. Si vous souhaitez modifier le récepteur, utilisez un pointeur tel que:

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

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

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

This l'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}
67
Abhishek Nalin