ChatGPT解决这个技术问题 Extra ChatGPT

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

go

很抱歉,我无法在问题标题中更具体,但我正在阅读一些 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 然后发表免责声明,说 stackoverflow 上的 Go 人员只回答不在 Tour of Go 上的问题。在 Haskell 社区中,人们可以提出 How can I get nth 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 问题并找到了这个。
非常感谢您提出这个问题并以这种方式表达它!

O
Oliver Williams

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

这里的一个问题是接收者像其他参数一样被推送到调用堆栈上,所以如果接收者是一个值类型,就像在 handler 的情况下,那么你将处理你从意义调用方法的东西的副本返回调用范围后,h.Name = "Evan" 之类的内容不会持续存在。出于这个原因,任何期望改变接收者状态的东西都需要使用指针或返回修改后的值(如果你正在寻找它,它会提供更多的不可变类型范例)。

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


链接到相关规范的良好解释和额外业力点
golang tour 也有一些非常有用的例子tour.golang.org/methods/1
还可能值得注意:s.BlockingClose() 等价于 (&s).BlockingClose()。这是因为 Go 识别(从方法 BlockingClose 的声明)接收者 s 应该是一个指针并将其视为指针。
我认为这是对如何将方法声明为函数的更好解释,例如:golang.org/ref/spec#Method_declarations
与 JS 类和这些类的方法的比较在这里特别好。
A
Aditya Kresna Permana

这意味着 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 },那么在此结构/对象上运行的函数(它们将调用记录器)是否应该具有指针或值的接收器?
M
Michael Freidgeim

如果您熟悉 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 中描述了值类型和指针之间的区别


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅