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

很抱歉,我不能在问题标题中更具体,但我正在阅读一些代码,我遇到了这种形式的函数声明:

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)是什么意思?考虑到括号之间的内容,整个函数声明意味着什么?

编辑

这不是围棋中函数和方法的区别是什么?的重复:这个问题来找我是因为我不知道函数名前括号里的东西是什么,而不是因为我想知道函数和方法之间有什么区别……如果我知道这个声明是一个方法,我一开始就不会有这个问题了。如果有一天有人和我有同样的疑惑,我不相信她会去寻找“戈朗方法”。因为她不知道情况是这样的。这就像想知道字母“sigma”;意思是在数学表达式之前(不知道它是求和的意思)有人说它是求和和其他东西的区别的复制。

而且,对这个问题的简短回答(“它是一个接收器”)并不能回答“功能和方法之间的区别是什么”。

64653 次浏览

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

这里的一个问题是,接收器像其他参数一样被推入调用堆栈,因此如果接收器是一个值类型,比如在handler的情况下,那么你将处理你调用方法的东西的副本,这意味着像h.Name = "Evan"这样的东西在你返回调用作用域后不会持续存在。出于这个原因,任何希望改变接收者状态的东西都需要使用指针或返回修改后的值(如果您正在寻找,则会提供更多的不可变类型范例)。

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

这意味着ServeHTTP不是一个独立的函数。函数名前的括号是定义这些函数操作的对象的Go方式。因此,本质上ServeHTTP是一个类型为handler的方法,可以使用任何类型为handler的对象调用,比如h。

h.ServeHTTP(w, r)

他们也被称为接收器。在那里是定义它们的两种方式。如果你想修改接收者,使用一个指针:

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

如果你不需要修改接收者,你可以将接收者定义为如下值:

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

来自Go playground的示例演示了这个概念。

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}

如果你熟悉c#扩展方法

一个go方法(具有特殊接收器参数的函数)。

func (v Vertex) Abs() float64

是不是类似c#的扩展方法

static float Abs( this Vertex v);

值类型和指针之间的区别在evanmcdonnal的回答中描述