很抱歉,我无法在问题标题中更具体,但我正在阅读一些 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”是什么意思(不知道它的意思是求和),有人说它是求和与其他事物之间区别的重复。
此外,对这个问题的简短回答(“它是一个接收者”)并没有回答“函数和方法之间有什么区别”。
n
th element from the list in Haskell? 之类的问题,这在 Learn you a Haskell for Great Good 的简介中,并且可以毫不费力地回答他们的问题。
这称为“接收器”。在第一种情况下 (h handler)
它是一个值类型,在第二种情况下 (s *GracefulServer)
它是一个指针。这在 Go 中的工作方式可能与其他一些语言有所不同。然而,接收类型的工作方式或多或少类似于大多数面向对象编程中的类。这是您调用该方法的东西,就像我将某个方法 A
放在某个类 Person
中,那么我需要一个 Person
类型的实例才能调用 A
(假设它是一个实例方法而不是静态的!)。
这里的一个问题是接收者像其他参数一样被推送到调用堆栈上,所以如果接收者是一个值类型,就像在 handler
的情况下,那么你将处理你从意义调用方法的东西的副本返回调用范围后,h.Name = "Evan"
之类的内容不会持续存在。出于这个原因,任何期望改变接收者状态的东西都需要使用指针或返回修改后的值(如果你正在寻找它,它会提供更多的不可变类型范例)。
这是规范中的相关部分; https://golang.org/ref/spec#Method_sets
这意味着 ServeHTTP
不是一个独立的函数。函数名前的括号是定义这些函数将操作的对象的 Go 方式。因此,本质上 ServeHTTP
是类型处理程序的方法,可以使用任何类型处理程序的对象(例如 h)来调用。
h.ServeHTTP(w, r)
它们也被称为接收器。 There 是定义它们的两种方式。如果要修改接收器,请使用如下指针:
func (s *MyStruct) pointerMethod() { } // method on pointer
如果您不需要修改接收器,您可以将接收器定义为如下值:
func (s MyStruct) valueMethod() { } // method on value
This 来自 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}
type Logger struct { lgr *zap.Logger }
,那么在此结构/对象上运行的函数(它们将调用记录器)是否应该具有指针或值的接收器?
如果您熟悉 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 中描述了值类型和指针之间的区别
s.BlockingClose()
等价于(&s).BlockingClose()
。这是因为 Go 识别(从方法 BlockingClose 的声明)接收者s
应该是一个指针并将其视为指针。