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

Mar*_*iro 196 go

对不起,我不能在问题标题中更具体,但我正在阅读一些Go代码,我遇到了这种形式的函数声明:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

func (s *GracefulServer) BlockingClose() bool {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

什么是(h handler)(s *GracefulServer)括号之间是什么意思?考虑到括号之间事物的含义,整个函数声明意味着什么?

编辑

与Go的功能和方法的区别什么不重复:这个问题来找我,因为我不知道函数名之前括号中的内容是什么,不是因为我想知道函数和方法之间有什么区别......如果我知道这个声明是一种方法我就不会'我们首先提出了这个问题.如果某人有一天和我有同样的疑问,我不相信她会去寻找"golang方法",因为她不知道情况就是这样.这就像想知道"sigma"字母在数学表达式之前的含义(不知道它意味着求和),并且有人说它是总和与其他事物之间差异的重复.

此外,这个问题的简短回答("它是接收者")无法回答"功能和方法之间的区别".

eva*_*nal 166

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

有一个问题在这里是接收器获取的情况下被推到像其他参数调用堆栈,所以如果接收者是一个值的类型,比如handler,你将在的东西拷贝一起工作你的意思是这样调用的方法h.Name = "Evan"会返回调用范围后不会保留.出于这个原因,任何期望改变接收器状态的东西都需要使用指针或返回修改后的值(如果你正在寻找它,则给出更多的不可变类型范例).

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

  • 链接到相关规范的良好解释和额外业力点 (4认同)
  • Golang游览也有一些非常有用的示例https://tour.golang.org/methods/1 (2认同)
  • 另外也许值得注意的是:“s.BlockingClose()”相当于“(&s).BlockingClose()”。这是因为 Go 认识到(从 BlockingClose 方法的声明中)接收者“s”应该是一个指针,并将其视为指针。 (2认同)

Abh*_*lin 77

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

h.ServeHTTP(w, r)
Run Code Online (Sandbox Code Playgroud)

它们也被称为接收器.两种方法可以定义它们.如果要修改接收器,请使用如下指针:

func (s *MyStruct) pointerMethod() { } // method on pointer
Run Code Online (Sandbox Code Playgroud)

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

func (s MyStruct)  valueMethod()   { } // method on value
Run Code Online (Sandbox Code Playgroud)

来自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)
Run Code Online (Sandbox Code Playgroud)

上述程序的输出是:

&{0 0}
&{0 0}
&{5 7}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案比公认的答案对我帮助更大。 (3认同)

MiF*_*vil 11

如果您熟悉C# 扩展方法

\n

go 方法(具有特殊接收器参数的函数)例如

\n
func (v Vertex) Abs() float64\n
Run Code Online (Sandbox Code Playgroud)\n

类似于c#扩展方法

\n
static float Abs( this Vertex v);\n
Run Code Online (Sandbox Code Playgroud)\n

值类型和指针之间的差异在evamcdonnal\xe2\x80\x99s 答案中描述

\n