Подтвердить что ты не робот

Синтаксис объявления функции: вещи в скобках перед именем функции

Извините, я не мог быть более конкретным в заголовке вопроса, но я читал код Go, и я столкнулся объявления функций этой формы:

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

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

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

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

Что означают (h handler) и (s *GracefulServer) между скобками? Что означает объявление всей функции, принимая во внимание смысл вещей между скобками?

Изменить

Это не дубликат В чем разница функций и методов в Go?: этот вопрос пришел ко мне, потому что я не знал, что в скобках до имени функции, а не потому, что я задавался вопросом, в чем разница между функциями и методами... если бы я знал, что это выражение было методом, у меня не было бы этого вопроса в первую очередь. Если у кого-то есть одно и то же сомнение, как я в один прекрасный день, я не верю, что она пойдет искать "методы голанга", потому что она не знает, что это так. Было бы интересно узнать, что означает буква "сигма" перед математическим выражением (не зная, что это означает суммирование), и кто-то говорит, что это дубликат того, что разница между суммированием и некоторой другой вещью.

Кроме того, короткий ответ на этот вопрос ( "это приемник" ) не отвечает на вопрос "какая разница между функциями и методами".

4b9b3361

Ответ 1

Это называется "приемником". В первом случае (h handler) это тип значения, во втором (s *GracefulServer) это указатель. Способ, которым это работает в Go, может немного отличаться от некоторых других языков. Однако тип приема работает более или менее как класс в большинстве объектно-ориентированных программ. Это то, на что вы вызываете метод, так же, как если бы я поместил некоторый метод A в сторону некоторого класса Person, тогда мне понадобился бы экземпляр типа Person, чтобы вызвать A (предположив, что это экземпляр метод, а не статический!).

Один из них заключается в том, что получатель попадает в стек вызовов, как и другие аргументы, поэтому, если получателем является тип значения, например, в случае handler, тогда вы будете работать над копией вещи, которую вы назвали метод, означающий что-то вроде h.Name = "Evan", не будет сохраняться после того, как вы вернетесь в область вызова. По этой причине все, что ожидает изменить состояние приемника, должно использовать указатель или возвращать измененное значение (дает больше парадигмы неизменяемого типа, если вы это ищете).

Здесь соответствующий раздел из спецификации; https://golang.org/ref/spec#Method_sets

Ответ 2

Это означает, что ServeHTTP не является автономной функцией. Скобкой перед именем функции является способ Go для определения объекта, на котором будут работать эти функции. Таким образом, по существу ServeHTTP является методом обработчика типа и может быть вызван с использованием любого объекта, например h, обработчика типа.

h.ServeHTTP(w, r)

Они также называются приемниками. Есть два способа их определения. Если вы хотите изменить приемник, используйте указатель, например:

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

Если вам не нужно модифицировать приемник, вы можете определить приемника как значение, например:

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

Этот пример из игровой площадки Go демонстрирует концепцию.

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)

Вывод указанной программы:

&{0 0}
&{0 0}
&{5 7}