来自公众号:新世界杂货铺
前言
在日常的开发中咱们除了定义函数以外, 咱们还会定义一些办法。这原本没有什么, 然而一些从PHP或者其余面向对象语言转GO的同学往往会把receiver name命名为this
, self
, me
等。
笔者在理论我的项目开发中也遇到相似的同学, 多次揭示却没有成果,于是信心写下这篇文章以便好好压服这些同学。
CR规范做法
首先咱们来看一下GO举荐的规范命名Receiver Names
,以下内容摘抄自https://github.com/golang/go/...:
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点:
- 办法接受者名称应反映其身份, 并且不要应用
me
,this
,self
这些面向对象语言的典型标志符。 - 在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
的时候,发现了一段非凡的代码,登时惊出一身冷汗,姑在本文补充一下,以避免本人和各位读者踩坑。
源代码截图如下:
惊出我一身冷汗的正是图中标红的局部,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()}
上述输入如下:
a.test()
可能失常输入,只有在解决变量构造体外部变量v
才报出panic!!!还好本文后面曾经介绍了Receiver是办法的第一个参数
。正因为是第一个参数所以仅仅作为参数传递时即便是nil
也可能失常调用函数,而在真正应用的中央报出panic。
鉴于receiver如此非凡,所以特意在本文实现之后补充后续内容以时刻揭示本人和各位读者。
本局部于20200827日晚补充。
最初, 祝各位事业有成!