Sintaxis de declaración de función: cosas entre paréntesis antes del nombre de la función

250

Lo siento, no podría ser más específico en el título de la pregunta, pero estaba leyendo un código Go y encontré declaraciones de función de esta forma:

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

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

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

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

¿Qué significa el (h handler)y el (s *GracefulServer)paréntesis entre? ¿Qué significa toda la declaración de función, teniendo en cuenta el significado de las cosas entre paréntesis?

Editar

Este no es un duplicado de ¿ Cuál es la diferencia de funciones y métodos en Go? : esta pregunta se me ocurrió porque no sabía cuáles eran las cosas entre paréntesis antes del nombre de la función, no porque me preguntara cuál era la diferencia entre funciones y métodos ... si supiera que esta declaración es un método, no lo haría He tenido esta pregunta en primer lugar. Si alguien tiene la misma duda que yo algún día, no creo que vaya a buscar "métodos de golang" porque no sabe que ese es el caso. Sería como preguntarse qué significa la letra "sigma" antes de una expresión matemática (sin saber que significa suma) y alguien dice que es un duplicado de cuál es la diferencia entre la suma y alguna otra cosa.

Además, la respuesta corta a esta pregunta ("es un receptor") no es una respuesta a "cuál es la diferencia entre funciones y métodos".

Marco Vinícius Monteiro
fuente
27
@Volker luego puso un descargo de responsabilidad diciendo que Go people en stackoverflow solo responde preguntas que no están en el Tour of Go. En la comunidad de Haskell, las personas pueden hacer preguntas como ¿Cómo puedo obtener el nelemento de la lista en Haskell? , que se encuentra en la Introducción sobre Aprenda un Haskell para un gran bien y obtenga respuestas a sus preguntas sin preocuparse por ello.
Marcus Vinícius Monteiro
23
Cuando tuve esta pregunta, primero fui al Go Tour. Revisé todos los títulos de "Función" y ninguno de los ejemplos cubrió esto. tour.golang.org/basics/4 tour.golang.org/basics/5 Si no sabe expandir Métodos e interfaces, no verá el título "Los métodos son funciones". Esta pregunta es válida y excelente para la indexación de Google. Los fanáticos de la bandera duplicada necesitan aligerarse.
Bruno Bronosky
14
¡Gracias por no ser específico en su pregunta, porque fue suficiente para ayudarme a encontrar la respuesta!
David K
1
Me preguntaste exactamente lo que buscaba, es una pregunta válida. Gracias. Leí todo tipo de definición de funciones y nadie me explicó esto. Todavía intenté escribir mi pregunta de nube y encontré esto.
Ajak6

Respuestas:

200

Esto se llama el "receptor". En el primer caso (h handler)es un tipo de valor, en el segundo (s *GracefulServer)es un puntero. La forma en que esto funciona en Go puede variar un poco de otros idiomas. Sin embargo, el tipo de recepción funciona más o menos como una clase en la mayoría de la programación orientada a objetos. Es de lo que se llama el método, al igual que si pongo algún método Aal lado de alguna clase Person, necesitaría una instancia de tipo Personpara llamar A(¡suponiendo que sea un método de instancia y no estático!).

Uno de gotcha aquí es que el receptor se inserta en la pila de llamadas al igual que otros argumentos por lo que si el receptor es un tipo de valor, al igual que en el caso de handlercontinuación, que va a trabajar en una copia de lo que llama el método de significar algo así como h.Name = "Evan"Would no persista después de que regrese al alcance de la llamada. Por esta razón, cualquier cosa que espere cambiar el estado del receptor, necesita usar un puntero o devolver el valor modificado (da más de un paradigma de tipo inmutable si está buscando eso).

Aquí está la sección relevante de la especificación; https://golang.org/ref/spec#Method_sets

evanmcdonnal
fuente
66
Buena explicación y puntos de karma adicionales para vincular a la especificación relevante
Marius Waldal
44
La gira de Golang tiene algunos ejemplos muy útiles también tour.golang.org/methods/1
tw_hoff
91

Significa ServeHTTPque no es una función independiente. El paréntesis antes del nombre de la función es la forma Go de definir el objeto sobre el cual operarán estas funciones. Entonces, esencialmente ServeHTTPes un método de manejador de tipos y se puede invocar usando cualquier objeto, digamos h, del manejador de tipos.

h.ServeHTTP(w, r)

También se les llama receptores. Hay dos formas de definirlos. Si desea modificar el receptor, use un puntero como:

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

Si no necesita modificar el receptor, puede definirlo como un valor como:

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

Este ejemplo de Go playground demuestra el concepto.

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)

La salida del programa anterior es:

&{0 0}
&{0 0}
&{5 7}
Abhishek Nalin
fuente