fatcat 枝头不见绿,蓄势待春风

go语法:将方法转换成普通函数

2019-02-19
fatcat22

在看以太坊的代码时,看到有这样一条语句:

  runtime.SetFinalizer(c, (*cache).finalizer)

其中cache是一个结构体,而c是一个*cache类型的变量。*cache有一个名为finalizer的方法,定义如下:

func (c *cache) finalizer() {
  .......
}

这里让我感到疑惑的是(*cache).finalizer这个表达式。先不管runtime.SetFinalizer对参数有什么要求,仅仅是这个表达式,我也没搞明白它是什么意思,甚至它怎么会是一个合法的表达式呢?

于是我尝试一顿搜索,终于找到了解释这个问题的官方文档

从这个文档中可以看出来,这种表达式有一个专门的名称,叫做”method expression”,中文可以翻译为“方法表达式”。简单来说,在go语言中,如果你为某个类型T定义了一个方法v,那么使用“T.v”这种方式,就可以生成一个和方法v相同的函数,但这个函数增加了一个参数,即第一个参数新增为一个T类型的参数。

文字描述比较绕,我们直接看例子吧。拿文章开头提到的表达式来说,由于finalizer*cache类开的方法,且它的定义是这样的:

func (c *cache) finalizer() {
  .......
}

那么(*cache).finalizer就生成了一个函数,这个函数应该是这样定义的:

f := func (c *cache) {
  .......
}

除此之外,它们的的函数体内容完全一致。

其实在描述”方法”的文档里,第一句话就是:

A method is a function with a receiver

即“方法是一种有接收者的函数”。以这种设计思路来看,“方法表达式”也就不奇怪了。

回头来看runtime.SetFinalizer的文档是这样描述它的参数的:

func SetFinalizer(obj interface{}, finalizer interface{})
The argument finalizer must be a function that takes a single argument to which obj’s type can be assigned, and can have arbitrary ignored return values.

也就是说它的第二个参数是一个函数,这个函数必须满足两个条件:

  1. 仅有一个参数,且runtime.SetFinalizer的第一个参数obj可以正常赋值给这个参数
  2. 返回值可以被忽略

根据上面对“方法表达式”的描述,(*cache).finalizer正好可以生成一个符合runtime.SetFinalizer第二个参数要求的函数。


Similar Posts

Comments