函数声明语法:函数名称前括号内的内容


247

抱歉,我无法在问题标题中更加具体,但是我正在阅读一些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中的功能和方法有何不同?:之所以问这个问题,是因为我不知道函数名之前括号中的内容是什么,不是因为我想知道函数和方法之间的区别是什么...如果我知道此声明是一个方法,我不会首先没有这个问题。如果有一天有人和我有同样的疑问,我不相信她会去寻找“ golang方法”,因为她不知道这种情况。这就像想知道字母“ sigma”在数学表达式之前是什么意思(不知道它表示求和),并且有人说这是求和与其他事物之间的区别的重复。

同样,对这个问题的简短回答(“它是一个接收者”)并不是对“函数和方法之间的区别”的回答。


27
@Volker随后发表免责声明,说stackoverflow上的Go人员仅回答不在Tour of Go中的问题。在Haskell社区中,人们可以提出诸如“ 如何n从Haskell列表中获取元素”之类的问题,位于“ 了解如何使您的Haskell成就卓越”的简介中,而无需大惊小怪地回答他们的问题。
MarcusViníciusMonteiro

23
当我有这个问题时,我首先去了Go Tour。我检查了所有“功能”标题,所有示例均未涉及。tour.golang.org/basics/4 tour.golang.org/basics/5如果您不知道扩展方法和接口,则不会看到“方法就是函数”标题。这个问题对Google索引是有效的,也很有效。重复的标志狂热者需要减轻。
Bruno Bronosky

14
感谢您在问题中没有具体说明,因为它足以帮助我找到答案!
David K

1
您问的正是我搜索的内容,它是一个有效的问题。谢谢。我读了各种函数定义,没有人解释。我仍然尝试编写我的nube问题,并发现了这个问题。
Ajak6

Answers:


198

这称为“接收器”。第一种情况(h handler)是值类型,第二种(s *GracefulServer)情况是指针。Go的工作方式可能与某些其他语言有所不同。但是,在大多数面向对象的编程中,接收类型或多或少像一个类。这是您从中调用方法的事情,就像如果我将某个方法A放在某个类的旁边,Person那么我将需要一个类型的实例Person才能进行调用A(假设它是一个实例方法而不是静态的!)。

这里有一个问题是,接收器获取的情况下被推到像其他参数调用堆栈,所以如果接收者是一个值的类型,比如handler,你将在的东西拷贝一起工作你的意思是这样调用的方法h.Name = "Evan"会返回调用范围后无法持久保存。由于这个原因,任何希望改变接收器状态的事物都需要使用指针或返回修改后的值(如果您正在寻找更多的不可变类型范例)。

这是规范中的相关部分;https://golang.org/ref/spec#Method_sets


6
很好的解释和与相关规范的链接的额外业
障积分

4
golang游览也有一些非常有用的示例tour.golang.org/methods/1
tw_hoff

90

这意味着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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.