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

Resuelto Marcus Vinícius Monteiro asked hace 8 años • 3 respuestas

Lamento no poder ser más específico en el título de la pregunta, pero estaba leyendo código Go y encontré declaraciones de funciones 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)entre paréntesis? ¿Qué significa toda la declaración de función, teniendo en cuenta el significado de las cosas entre paréntesis?

Editar

Esto no es un duplicado de ¿Cuál es la diferencia entre funciones y métodos en Go? : esta pregunta me surgió 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, lo haría En primer lugar, no he tenido esta pregunta. Si alguien tiene la misma duda que yo algún día, no creo que busque "métodos golang" porque no sabe que ese es el caso. Sería como preguntarse qué significa la letra "sigma" delante 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 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".

Aceptado

Esto se llama "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 con respecto a otros idiomas. El tipo receptor, sin embargo, funciona más o menos como una clase en la mayoría de la programación orientada a objetos. Es desde donde llamas al método, muy parecido a si pongo algún método Adentro de alguna clase Person, entonces necesitaría una instancia de tipo Personpara poder llamar A(¡asumiendo que es un método de instancia y no estático!).

Un problema aquí es que el receptor se empuja a la pila de llamadas como otros argumentos, por lo que si el receptor es un tipo de valor, como en el caso de, handlerentonces estará trabajando en una copia de lo que llamó al método, lo que significa algo como h.Name = "Evan"lo haría. no persiste después de regresar 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 avatar Dec 01 '2015 23:12 evanmcdonnal

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 en el que operarán estas funciones. Entonces, esencialmente ServeHTTPes un método de controlador de tipo y se puede invocar usando cualquier objeto, digamos h, de controlador de tipo.

h.ServeHTTP(w, r)

También se les llama receptores. Hay dos formas de definirlos. Si desea modificar el receptor utilice 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)

El resultado del programa anterior es:

&{0 0}
&{0 0}
&{5 7}
Abhishek Nalin avatar Dec 18 '2015 07:12 Abhishek Nalin

Si está familiarizado con los métodos de extensión de C# ,

un método go ( una función con un argumento receptor especial ), por ejemplo

func (v Vertex) Abs() float64

es similar al método de extensión c#

static float Abs( this Vertex v);

Las diferencias entre tipos de valores y punteros se describen en la respuesta de Evanmcdonnal.

Michael Freidgeim avatar Mar 12 '2021 22:03 Michael Freidgeim