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


250

Я сожалею, что не мог быть более конкретным в названии вопроса, но я читал некоторый код 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? : этот вопрос пришел ко мне, потому что я не знал, что было в скобках перед именем функции, а не потому, что мне было интересно, в чем разница между функциями и методами ... если бы я знал, что это объявление было методом, я бы не стал у меня был этот вопрос в первую очередь. Если когда-нибудь у меня возникнут те же сомнения, что и у меня, я не верю, что она будет искать «методы Голанга», потому что она не знает, что это так. Это все равно, что задаться вопросом, что означает буква «сигма» перед математическим выражением (не зная, что это означает суммирование), и кто-то говорит, что это дубликат различия между суммированием и чем-то другим.

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


27
Затем @Volker поставил заявление об отказе от ответственности, в котором говорится, что люди Go на stackoverflow отвечают только на вопросы, которых нет в Tour of Go. В сообществе Haskell люди могут задавать вопросы, например, Как я могу получить этот nэлемент из списка в Haskell? , который находится во введении к изучению Haskell для большого блага, и получить ответы на свои вопросы без суеты об этом.
Маркус Винициус Монтейро

23
Когда у меня возник этот вопрос, я впервые отправился в Го Тур. Я проверил все заголовки «Function», и ни один из примеров не охватывал это. tour.golang.org/basics/4 tour.golang.org/basics/5 Если вы не знаете, как расширить методы и интерфейсы, вы не увидите заголовок «Методы являются функциями». Этот вопрос действителен и отлично подходит для индексации Google. Двойной флаг фанатиков нужно осветлить.
Бруно Броноски

14
Спасибо, что не уточнили свой вопрос, потому что этого было достаточно, чтобы помочь мне найти ответ!
Дэвид К

1
Вы задали именно то, что я искал, это правильный вопрос. Спасибо. Я прочитал все виды определения функций, и никто не объяснил это. Я все еще пытался написать мой вопрос и нашел это.
Ajak6

Ответы:


200

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

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

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


6
Хорошее объяснение и дополнительные очки кармы для связи с соответствующей спецификацией
Marius Waldal

4
У тура по Голангу есть и довольно полезные примеры. Tour.golang.org/methods/1
tw_hoff

91

Это означает, что ServeHTTPэто не отдельная функция. Круглая скобка перед именем функции - это способ определения объекта, с которым будут работать эти функции. Таким образом, по сути 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}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.