对不起,我不能在问题标题中更具体,但我正在阅读一些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>
答案 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