來自公眾號:新世界雜貨鋪
文章目錄
- 前言
- CR標準做法
- Receiver是方法的第一個引數!
- Receiver是可以為nil的!!!
前言
在日常的開發中我們除了定義函式以外, 我們還會定義一些方法,這本來沒有什么, 但是一些從PHP或者其他面向物件語言轉GO的同學往往會把receiver name命名為this, self, me等,
筆者在實際專案開發中也遇到類似的同學, 屢次提醒卻沒有效果,于是決心寫下這篇文章以便好好說服這些同學,
CR標準做法
首先我們來看一下GO推薦的標準命名Receiver Names,以下內容摘抄自https://github.com/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點:
- 方法接受者名稱應反映其身份, 并且不要使用
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: 1
value: 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:
3
3
demo2:
4
6
看上面的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日晚補充,
最后, 祝各位事業有成!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/152700.html
標籤:其他
