Синтаксис оголошення функції: речі в дужках перед назвою функції


249

Вибачте, що я не міг бути більш конкретним у назві питання, але я читав деякий код 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? , що міститься у Вступі до Learn you Haskell for Great Good і отримайте відповіді на їх запитання без суєти.
Маркус Вініцій Монтеїро

23
Коли у мене виникло це питання, я спершу вирушив на екскурсію Go. Я перевірив усі назви "Функції" і жоден із прикладів цього не висвітлював. 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"означає не зберігається після повернення до області виклику. З цієї причини все, що очікує зміни стану приймача, потребує використання покажчика або повернення зміненого значення (дає більше парадигми непорушного типу, якщо ви цього шукаєте).

Ось відповідний розділ із специфікації; https://golang.org/ref/spec#Method_sets


6
Гарне пояснення та додаткові моменти карми для посилання на відповідну специфікацію
Маріус Вальдал

4
Галанг-тур має також досить корисні приклади tour.golang.org/methods/1
tw_hoff

90

Це означає, що 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.