函数声明语法:函数名前括号内的东西
Posted
技术标签:
【中文标题】函数声明语法:函数名前括号内的东西【英文标题】:Function declaration syntax: things in parenthesis before function name 【发布时间】:2016-03-06 01:09:53 【问题描述】:很抱歉,我无法在问题标题中更具体,但我正在阅读一些 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”是什么意思(不知道它的意思是求和),有人说它是求和与其他事物之间区别的重复。
此外,对这个问题(“它是一个接收器”)的简短回答不能回答“函数和方法之间有什么区别”。
【问题讨论】:
@Volker 然后发表免责声明,称 *** 上的 Go 人员只回答不在 Tour of Go 上的问题。在 Haskell 社区中,人们可以提出How can I getn
th element from the list in Haskell? 之类的问题,该问题位于Learn you a Haskell for Great Good 的简介中,并且可以毫不费力地回答他们的问题。
当我有这个问题时,我首先去了Go Tour。我检查了所有的“功能”标题,但没有一个例子涵盖这一点。 tour.golang.org/basics/4 tour.golang.org/basics/5 如果你不知道扩展方法和接口,你不会看到“方法就是函数”的标题。这个问题对谷歌索引是有效的和伟大的。重复的旗帜***者需要点亮。
感谢您没有具体说明您的问题,因为这足以帮助我找到答案!
你问的正是我搜索的内容,这是一个有效的问题。谢谢你。我阅读了所有类型的函数定义,但没有人解释这一点。我仍然尝试写我的 nube 问题并找到了这个。
非常感谢您提出这个问题并以这种方式表达它!
【参考方案1】:
这称为“接收器”。在第一种情况下(h handler)
它是一个值类型,在第二种情况下(s *GracefulServer)
它是一个指针。这在 Go 中的工作方式可能与其他一些语言有所不同。然而,接收类型的工作方式或多或少类似于大多数面向对象编程中的类。这是您调用该方法的东西,就像我将一些方法 A
放在某个类 Person
中,那么我需要一个 Person
类型的实例才能调用 A
(假设它是一个实例方法而不是静态的!)。
这里的一个问题是接收者像其他参数一样被推入调用堆栈,所以如果接收者是一个值类型,比如handler
,那么你将处理你调用的东西的副本返回调用范围后,h.Name = "Evan"
之类的方法不会持续存在。出于这个原因,任何期望改变接收者状态的东西都需要使用指针或返回修改后的值(如果你正在寻找它,它会提供更多的不可变类型范例)。
这是规范中的相关部分; https://golang.org/ref/spec#Method_sets
【讨论】:
很好的解释和额外的业力点,用于链接到相关规范 golang 之旅也有一些非常有用的例子tour.golang.org/methods/1 也可能值得注意:s.BlockingClose()
等价于(&s).BlockingClose()
。这是因为 Go 识别(从方法 BlockingClose 的声明)接收者 s
应该是一个指针并将其视为指针。
我认为这是对如何将方法声明为函数的更好解释,例如:golang.org/ref/spec#Method_declarations【参考方案2】:
这意味着ServeHTTP
不是一个独立的函数。函数名前的括号是定义这些函数将操作的对象的 Go 方式。所以,ServeHTTP
本质上是一个 handler 类型的方法,可以使用任何 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 := &Mutatable0, 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
,操作这个结构/对象的函数(它们将调用记录器)是否应该有指针或值的接收器?【参考方案3】:
如果你熟悉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
【讨论】:
以上是关于函数声明语法:函数名前括号内的东西的主要内容,如果未能解决你的问题,请参考以下文章