Sintaxe de declaração de função: itens entre parênteses antes do nome da função


248

Sinto muito, mas não pude ser mais específico no título da pergunta, mas estava lendo algum código Go e encontrei declarações de função deste formulário:

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

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

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

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

O que significa o parêntese (h handler)e (s *GracefulServer)entre? O que significa toda a declaração de função, levando em consideração o significado das coisas entre parênteses?

Editar

Esta não é uma duplicata de Qual a diferença de funções e métodos no Go? : essa pergunta veio a mim porque eu não sabia o que estavam entre parênteses antes do nome da função, não porque me perguntava qual era a diferença entre funções e métodos ... se soubesse que essa declaração era um método, não saberia ' Não tive essa pergunta em primeiro lugar. Se alguém tiver a mesma dúvida que eu um dia, não acredito que ela vá procurar "métodos golang" porque não sabe que esse é o caso. Seria como imaginar o que a letra "sigma" significa antes de uma expressão matemática (não saber que significa soma) e alguém diz que é uma duplicata da diferença entre soma e alguma outra coisa.

Além disso, a resposta curta a essa pergunta ("é um receptor") não é resposta para "qual é a diferença entre funções e métodos".


27
O @Volker coloca um aviso dizendo que o pessoal do Go no stackoverflow responde apenas a perguntas que não estão no Tour of Go. Na comunidade Haskell, as pessoas podem fazer perguntas como Como obter o nelemento da lista em Haskell? , que está na Introdução sobre o aprendizado de um Haskell para um bom bem, e obtém respostas para suas perguntas sem se preocupar com isso.
Marcus Vinícius Monteiro

23
Quando eu tive essa pergunta, fui pela primeira vez ao Go Tour. Eu verifiquei todos os títulos de "Função" e nenhum dos exemplos abordou isso. tour.golang.org/basics/4 tour.golang.org/basics/5 Se você não souber expandir Métodos e interfaces, não verá o título "Métodos são funções". Esta questão é válida e ótima para indexação do Google. Os fanáticos duplicados da bandeira precisam se iluminar.
Bruno Bronosky

14
Obrigado por não ser específico na sua pergunta, porque foi o suficiente para me ajudar a encontrar a resposta!
David K

1
Você perguntou exatamente o que eu procurei, é uma pergunta válida. Obrigado. Eu li todo o tipo de definição de função e ninguém explicou isso. Eu ainda tentei escrever minha pergunta nube e encontrei isso.
Ajak6

Respostas:


199

Isso é chamado de 'receptor'. No primeiro caso (h handler), é um tipo de valor, no segundo (s *GracefulServer), é um ponteiro. A maneira como isso funciona no Go pode variar um pouco em relação a outros idiomas. O tipo de recebimento, no entanto, funciona mais ou menos como uma classe na maioria das programações orientadas a objetos. É o que você chama de método, assim como se eu colocasse algum método Ade lado em alguma classe Person, eu precisaria de uma instância do tipo Personpara chamar A(assumindo que seja um método de instância e não estático!).

Uma pegadinha aqui é que o receptor é empurrado para a pilha de chamadas como outros argumentos por isso, se o receptor é um tipo de valor, como no caso de handler, em seguida, você estará trabalhando em uma cópia da coisa que você chamou o método de significar algo como h.Name = "Evan"Would não persistirá depois que você retornar ao escopo da chamada. Por esse motivo, qualquer coisa que espere alterar o estado do receptor, precisa usar um ponteiro ou retornar o valor modificado (fornece um paradigma de tipo imutável, se você estiver procurando por isso).

Aqui está a seção relevante da especificação; https://golang.org/ref/spec#Method_sets


6
Boa explicação e pontos de karma extras para a ligação com a especificação relevante
Marius Waldal

4
O tour golang também tem alguns exemplos bastante úteis tour.golang.org/methods/1
tw_hoff 25/06/18

90

Isso significa que ServeHTTPnão é uma função autônoma. O parêntese antes do nome da função é a maneira correta de definir o objeto no qual essas funções irão operar. Portanto, essencialmente ServeHTTPé um método do manipulador de tipos e pode ser chamado usando qualquer objeto, digamos h, do manipulador de tipos.

h.ServeHTTP(w, r)

Eles também são chamados de receptores. Existem duas maneiras de defini-las. Se você deseja modificar o receptor, use um ponteiro como:

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

Se você não precisar modificar o receptor, poderá defini-lo como um valor como:

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

Este exemplo do playground Go demonstra o conceito.

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)

A saída do programa acima é:

&{0 0}
&{0 0}
&{5 7}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.