Go面試必考題目之method篇
在Go的類方法中,分為值接收者方法和指標接收者方法,對於剛開始接觸Go的同學來說,有時對Go的方法會感到困惑。下面我們結合題目來學習Go的方法。
為了方便敘述,下文描述的值接收者方法簡寫為值方法,指標接收者方法簡寫為指標方法。
下面程式碼中,哪段編號的程式碼會報錯?具體報什麼錯誤?
type Animal interface {
Bark()
}
type Dog struct {
}
func (d Dog) Bark() {
fmt.Println("dog")
}
type Cat struct {
}
func (c *Cat) Bark() {
fmt.Println("cat")
}
func Bark(a Animal) {
a.Bark()
}
func getDog() Dog {
return Dog{}
}
func getCat() Cat {
return Cat{}
}
func main() {
dp := &Dog{}
d := Dog{}
dp.Bark() // (1)
d.Bark() // (2)
Bark(dp) // (3)
Bark(d) // (4)
cp := &Cat{}
c := Cat{}
cp.Bark() // (5)
c.Bark() // (6)
Bark(cp) // (7)
Bark(c) // (8)
getDog().Bark() // (9)
getCat().Bark() // (10)
}
拋磚引玉,讓我們學習完再來作答。
值方法和指標方法
我們來看看值方法的宣告。
type Dog struct {
}
func (d Dog) Bark() {
fmt.Println("dog")
}
上面程式碼中,方法Bark
的接收者是值型別,那麼這就是一個值接收者的方法。
下面再看看指標接收者的方法。
type Cat struct {
}
func (c *Cat) Bark() {
fmt.Println("cat")
}
類的方法集合
這個在Go文件裡有定義:
- 對於型別
T
,它的方法集合是所有接收者為T
的方法。 - 對於型別
*T
,它的方法集合是所有接收者為*T
和T
的方法。
Values | Method Sets |
---|---|
T | (t T) |
*T | (t T) and (t *T) |
方法的呼叫者
*指標`T接收者方法**:只有指標型別
T才能呼叫,但其實值
T型別也能呼叫,為什麼呢?因為當使用值呼叫
t.Call()時,Go會轉換成
(&t).Call(),也就是說最後呼叫的還是接收者為指標
T`的方法。
但要注意t是要能取地址才能這麼呼叫,比如下面這種情況就不行:
func getUser() User {
return User{}
}
...
getUser().SayWat()
// 編譯錯誤:
// cannot call pointer method on aUser()
// cannot take the address of aUser()
值T 接收者方法: 指標型別*T 和值T 型別都能呼叫。
Methods Receivers |
Values |
---|---|
(t T) | T and *T |
(t *T) | *T |
使用接收者為*T
的方法實現一個介面,那麼只有那個型別的指標*T
實現了對應的介面。
如果使用接收者為T
的方法實現一個介面,那麼這個型別的值T
和指標*T
都實現了對應的介面。
宣告建議
在給類宣告方法時,方法接收者的型別要統一,最好不要同時宣告接收者為值和指標的方法,這樣容易混淆而不清楚到底實現了哪些介面。
下面我們來看看哪種型別適合宣告接收者為值或指標的方法。
指標接收者方法
下面這2種情況請務必宣告指標接收者方法:
- 方法中需要對接收者進行修改的。
- 類中包含
sync.Mutex
或類似鎖的變數,因為它們不允許值拷貝。
下面這2種情況也建議宣告指標接收者方法:
- 類成員很多的,或者大陣列,使用指標接收者效率更高。
- 如果拿不準,那也宣告接收者為指標的方法吧。
值接收者方法
下面這些情況建議使用值接收者方法:
- 型別為
map
,func
,channel
。 - 一些基本的型別,如
int
,string
。 - 一些小陣列,或小結構體並且不需要修改接收者的。
題目解析
type Animal interface {
Bark()
}
type Dog struct {
}
func (d Dog) Bark() {
fmt.Println("dog")
}
type Cat struct {
}
func (c *Cat) Bark() {
fmt.Println("cat")
}
func Bark(a Animal) {
a.Bark()
}
func getDog() Dog {
return Dog{}
}
func getCat() Cat {
return Cat{}
}
func main() {
dp := &Dog{}
d := Dog{}
dp.Bark() // (1) 通過
d.Bark() // (2) 通過
Bark(dp)
// (3) 通過,上面說了型別*Dog的方法集合包含接收者為*Dog和Dog的方法
Bark(d) // (4) 通過
cp := &Cat{}
c := Cat{}
cp.Bark() // (5) 通過
c.Bark() // (6) 通過
Bark(cp) // (7) 通過
Bark(c)
// (8) 編譯錯誤,值型別Cat的方法集合只包含接收者為Cat的方法
// 所以T並沒有實現Animal介面
getDog().Bark() // (9) 通過
getCat().Bark()
// (10) 編譯錯誤,
// 上面說了,getCat()是不可地址的
// 所以不能呼叫接收者為*Cat的方法
}
總結
- 理清型別的方法集合。
- 理清接收者方法的呼叫範圍。
參考文獻
- 《Pointer vs Value receiver》 https://yourbasic.org/golang/pointer-vs-value-receiver/
- 《Method sets》 https://golang.org/ref/spec#Method_sets
- https://stackoverflow.com/questions/19433050/go-methods-sets-calling-method-for-pointer-type-t-with-receiver-t?rq=1
感謝閱讀,歡迎大家指正,留言交流~
相關文章
- Go面試必考題目之slice篇Go面試
- 分享一道Go面試必考的題Go面試
- 面試必考:網路問題面試
- 100家IT 名企面試必考面試題java系列面試題Java
- 2018最新《BAT Java必考面試題集》BATJava面試題
- Java面試題:之ZooKeeper篇Java面試題
- Android面試題之Fragment篇Android面試題Fragment
- 面試題整理之Vue篇面試題Vue
- 大型網際網路公司必考java面試題與面試技巧Java面試題
- js面試必考三問JS面試
- 2019年,Python工程師必考的6個面試題,Python面試題No5Python工程師面試題
- Android面試題之Gradle配置篇Android面試題Gradle
- 面試題聯盟之 VUE 篇面試題Vue
- Go 面試題Go面試題
- TX 面試題目面試題
- 「高頻必考」Docker&K8S面試題和答案DockerK8S面試題
- iPhone 常用面試題目iPhone面試題
- SQL面試必考——計算留存率SQL面試
- 測試面試題目求解答面試題
- python實戰之爬蟲面試必備題目Python爬蟲面試
- 限時看!阿里、華為資料結構面試必考題!阿里資料結構面試
- mysql面試常見題目MySql面試
- 變態的面試題目面試題
- 蛇皮的Python面試題目Python面試題
- 前端面試送命題:面試題篇前端面試題
- 面試python的必考題,收藏好了!拿高薪就靠它了面試Python高薪
- 面向面試之 HTML 篇面試HTML
- 面向面試之 CSS 篇面試CSS
- 面試之道之效能篇面試
- Java面試必考題之執行緒的生命週期,結合原始碼,透徹講解!Java面試執行緒原始碼
- defer問題——面試Go必看面試Go
- go面試題-基礎類Go面試題
- 面試必考:秒殺系統如何設計?面試
- AI筆試面試題庫-Python題目解析1AI筆試面試題Python
- AI筆試面試題庫-Python題目解析3AI筆試面試題Python
- AI筆試面試題庫-Python題目解析4AI筆試面試題Python
- 測試面試題-積累篇面試題
- 面試題目-遍歷,點選面試題