为什么go中的receiver name不推荐使用this或者者self

作者 : 开心源码 本文共2068个字,预计阅读时间需要6分钟 发布时间: 2022-05-13 共252人阅读

前言

在日常的开发中我们除了定义函数以外, 我们还会定义少量方法。这原本没有什么, 但是少量从PHP或者者其余面向对象语言转GO的同学往往会把receiver name命名为this, self, me等。

笔者在实际项目开发中也遇到相似的同学, 多次提示却没有效果,于是决心写下这篇文章以便好好说服这些同学。

CR标准做法

首先我们来看一下GO推荐的标准命名Receiver Names,以下内容摘抄自 golang/go/wiki/CodeReviewComments#receiver-names:

The name of a method's receiver should be a reflection of its identity;often a one or two letter abbreviation of its type suffices (such as "c" or "cl" for "Client"). Don't use generic names such as "me", "this" or "self", identifiers typical of object-oriented languages that gives the method a special meaning. In Go, the receiver of a method is just another parameter and therefore, should be named accordingly. ...

简单翻译总结有如下2点:

  1. 方法接受者名称应反映其身份, 并且不要使用me, this, self这些面向对象语言的典型标志符。
  2. 在go中方法接受者其实就是方法的另一个参数。

Receiver是方法的第一个参数!

上面的第二点, 可能不是很好了解,所以我们直接看下面的demo:

// T ...type T int// Println ...func (t T) Println() {    fmt.Println("value: %v", t)}func main() {    t := T(1)    t.Println()    T.Println(t) // receiver作为函数的第一个参数,这个时候发生值拷贝,所以方法内部的t变量只是真实t变量的一个拷贝,这和this的含义是不相符的}// output:value: 1value: 1

通过上面的demo, 我们知道接受者可以直接作为第一个参数传递给方法的。而t.Println()应该就是Go中的一种语法糖了。

到这里可能有同学又要问了, 既然Go提供了这种语糖,那我们这样命名有什么问题呢?笔者先不焦急解释, 我们继续看下面的demo:

// Test ...type Test struct {    A int}// SetA ...func (t Test) SetA(a int) {    t.A = a}// SetA1 ...func (t *Test) SetA1(a int) {    t.A = a}func main() {    t := Test{        A: 3,    }    fmt.Println("demo1:")    fmt.Println(t.A)    t.SetA(5)    fmt.Println(t.A)    t1 := Test{        A: 4,    }    fmt.Println("demo2:")    fmt.Println(t1.A)    (&t1).SetA1(6)    fmt.Println(t1.A)}// output:demo1:33demo2:46

看上面的demo我们知道, 当receiver不是指针时调用SetA其值根本没有改变。

由于Go中都是值传递,所以你假如对SetA的receiver的名称命名为this, self等,它就已经失去了本身的意义——“调用一个对象的方法就是向该对象传递一条消息”。而且对象本身的属性也并不肯定会发生改变。

综上: 请各位读者在对receiver命名时不要再用this, self等具备特殊含义的名称啦。

Receiver是可以为nil的!!!

最近在研读h2_bundle.go的时候,发现了一段特殊的代码,顿时惊出一身冷汗,姑在本文补充一下,以防止自己和各位读者踩坑。

源代码截图如下:

image

惊出我一身冷汗的正是图中标红的部分,receiver居然还要判断为nil!在我的潜意识里一直是这样认为的,receiver默认都是有值的,直接使用就行了。这简直颠覆我的认知,吓得我赶紧写了个demo验证一下:

type A struct {    v int}func (a *A) test() {    fmt.Println(a == nil)}func (a *A) testV() {    fmt.Println(a.v)}func main() {    var a *A    a.test()    a.testV()}

上述输出如下:

image

a.test()能够正常输出,只有在解决变量结构体内部变量v才报出panic!!!还好本文前面已经详情了Receiver是方法的第一个参数。正由于是第一个参数所以仅仅作为参数传递时即便是nil也能够正常调用函数,而在真正使用的地方报出panic。

鉴于receiver如此特殊,所以特意在本文完成之后补充后续内容以时刻提示自己和各位读者。

本部分于20200827日晚补充。

最后, 祝各位事业有成!

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 为什么go中的receiver name不推荐使用this或者者self

发表回复