Синтаксис объявления функции: вещи в скобках перед именем функции
Извините, я не мог быть более конкретным в заголовке вопроса, но я читал код 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?: этот вопрос пришел ко мне, потому что я не знал, что в скобках до имени функции, а не потому, что я задавался вопросом, в чем разница между функциями и методами... если бы я знал, что это выражение было методом, у меня не было бы этого вопроса в первую очередь. Если у кого-то есть одно и то же сомнение, как я в один прекрасный день, я не верю, что она пойдет искать "методы голанга", потому что она не знает, что это так. Было бы интересно узнать, что означает буква "сигма" перед математическим выражением (не зная, что это означает суммирование), и кто-то говорит, что это дубликат того, что разница между суммированием и некоторой другой вещью.
Кроме того, короткий ответ на этот вопрос ( "это приемник" ) не отвечает на вопрос "какая разница между функциями и методами".
Ответы
Ответ 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}