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

huangapple go评论78阅读模式
英文:

Function declaration syntax: things in parenthesis before function name

问题

我很抱歉,我无法提供标题中更具体的信息,但我正在阅读一些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)是什么意思?整个函数声明的含义是什么,考虑到括号中的内容的含义?

编辑

这不是 https://stackoverflow.com/questions/8263546/whats-the-difference-of-functions-and-methods-in-google-go 的重复问题:我之所以提出这个问题,是因为我不知道函数名前括号中的内容是什么,而不是因为我想知道函数和方法之间的区别...如果我知道这个声明是一个方法,我一开始就不会有这个问题。如果有人有和我一样的疑问,我不相信她会去搜索“golang方法”,因为她不知道这是这种情况。这就像想知道数学表达式中字母“sigma”表示什么(不知道它表示求和)的意思,然后有人说它是关于求和和其他某个东西的区别的重复问题。

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

英文:

I'm sorry I couldn't be more specific in the question title, but I was reading some Go code and I encountered function declarations of this form:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ...
}

from https://github.com/mattermost/platform/blob/master/api/context.go

func (s *GracefulServer) BlockingClose() bool {
    ...
}

from https://github.com/braintree/manners/blob/master/server.go

What does the (h handler) and the (s *GracefulServer) between parenthesis mean? What does the entire function declaration mean, taking into account the meaning of the things between parenthesis?

Edit

This is not a duplicate of https://stackoverflow.com/questions/8263546/whats-the-difference-of-functions-and-methods-in-google-go : this question came to me because I didn't know what the things in parenthesis before the function name were, not because I wondered what was the difference between functions and methods... if I knew that this declaration was a method I wouldn't have had this question in the first place. If someone has the same doubt as me one day, I don't believe she will go searching for "golang methods" because she doesn't know that this is the case. It would be like wondering what the letter "sigma" means before a mathematical expression (not knowing it means summation) and someone says it's a duplicate of what's the difference between summation and some other thing.

Also, the short answer to this question ("it's a receiver") is no answer to "what's the difference between functions and methods".

答案1

得分: 405

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

这里有一个需要注意的地方是,接收器像其他参数一样被推送到调用栈上,所以如果接收器是一个值类型,就像在handler的情况下,那么你将在调用方法的副本上工作,这意味着像h.Name = "Evan"这样的操作在返回到调用范围后不会持久存在。因此,任何希望改变接收器状态的操作都需要使用指针或返回修改后的值(如果你正在寻找更多的不可变类型范式)。

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

英文:

This is called the 'receiver'. In the first case (h handler) it is a value type, in the second (s *GracefulServer) it is a pointer. The way this works in Go may vary a bit from some other languages. The receiving type, however, works more or less like a class in most object-oriented programming. It is the thing you call the method from, much like if I put some method A inside some class Person then I would need an instance of type Person in order to call A (assuming it's an instance method and not static!).

One gotcha here is that the receiver gets pushed onto the call stack like other arguments so if the receiver is a value type, like in the case of handler then you will be working on a copy of the thing you called the method from meaning something like h.Name = "Evan" would not persist after you return to the calling scope. For this reason, anything that expects to change the state of the receiver needs to use a pointer or return the modified value (gives more of an immutable type paradigm if you're looking for that).

Here's the relevant section from the spec; https://golang.org/ref/spec#Method_sets

答案2

得分: 173

这意味着ServeHTTP不是一个独立的函数。函数名前面的括号是Go语言中定义这些函数将操作的对象的方式。因此,ServeHTTP实际上是类型为handler的方法,并且可以使用任何类型为handler的对象(比如h)来调用。

h.ServeHTTP(w, r)

这些也被称为接收器(receivers)。有两种定义它们的方式。如果你想修改接收器,请使用指针,例如:

func (s *MyStruct) pointerMethod() { } // 指针方法

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

func (s MyStruct) valueMethod()   { } // 值方法

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}
英文:

It means ServeHTTP is not a standalone function. The parenthesis before the function name is the Go way of defining the object on which these functions will operate. So, essentially ServeHTTP is a method of type handler and can be invoked using any object, say h, of type handler.

h.ServeHTTP(w, r)

They are also called receivers. There are two ways of defining them. If you want to modify the receiver use a pointer like:

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

If you dont need to modify the receiver you can define the receiver as a value like:

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

This example from Go playground demonstrates the concept.

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)

The output of the above program is :

&{0 0}
&{0 0}
&{5 7}

答案3

得分: 10

如果你熟悉C#的扩展方法,那么Go语言中的go方法(带有特殊接收器参数的函数)类似于C#的扩展方法。例如:

func (v Vertex) Abs() float64

类似于C#的扩展方法:

static float Abs(this Vertex v);

有关值类型和指针之间的区别,请参考evanmcdonnal的回答。

英文:

If you are familiar with c# extension methods,

a go method (a function with a special receiver argument) e.g.

func (v Vertex) Abs() float64

is similar to c# extension method

static float Abs( this Vertex v);

The differences between value types and pointers are described in evanmcdonnal’s answer

huangapple
  • 本文由 发表于 2015年12月2日 06:56:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/34031801.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定