函数声明语法:函数名前的括号内的东西

时间:2015-12-01 22:56:53

标签: go

对不起,我不能在问题标题中更具体,但我正在阅读一些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)是什么意思?考虑到括号之间事物的含义,整个函数声明意味着什么?

修改

这不是Whats the difference of functions and methods in Go?的重复:这个问题来找我,因为我在函数名称之前不知道括号中的内容是什么,而不是因为我想知道函数和函数之间的区别是什么方法......如果我知道这个宣言是一种方法,我首先不会有这个问题。如果某人有一天和我有同样的疑问,我不相信她会去寻找" golang方法"因为她不知道情况就是这样。这就像想知道这封信" sigma"在数学表达式之前(不知道它意味着总和),并且有人说它与总和与其他事物之间的区别重复。

此外,这个问题的简短回答(&#34;它是接收者&#34;)无法回答&#34;功能和方法之间的区别&#34;。< / p>

3 个答案:

答案 0 :(得分:136)

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

这里有一个问题是接收器像其他参数一样被推入调用堆栈,因此如果接收器是值类型,就像A那样,那么你将会处理你的副本在返回调用范围后,从handler这样的意义调用方法将不会持久存在。出于这个原因,任何期望改变接收器状态的东西都需要使用指针或返回修改后的值(如果你正在寻找它,可以提供更多的不可变类型范例)。

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

答案 1 :(得分:56)

这意味着ServeHTTP不是一个独立的功能。函数名之前的括号是定义这些函数将在其上运行的对象的Go方式。所以,基本上ServeHTTP是一个类型处理程序的方法,可以使用类型为handler的任何对象调用,例如h。

h.ServeHTTP(w, r)

它们也被称为接收器。 There是定义它们的两种方式。如果要修改接收器,请使用如下指针:

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

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

func (s MyStruct)  valueMethod()   { } // method on value
Go操场上的

This示例演示了这个概念。

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}

答案 2 :(得分:2)

如果您熟悉 c# extension methods

go 方法 (a function with a special receiver argument) 例如

func (v Vertex) Abs() float64

类似于c#扩展方法

static float Abs( this Vertex v);

值类型和指针的区别见evanmcdonnal’s answer