Go 裏面的接口,絕對是我入坑程序員以來覺得最坑的一個東西了。爲什麼說它坑,就是怎麼看怎麼彆扭。
說明
Go 中的接口是由使用者來定義的。這和傳統的 接口 有點不一樣(當然我們在開發的過程中可以根據具體的情況去決定誰用接口)
看一個例子:
// package mooc
type Retriever struct {
Contents string
}
func (r Retriever) Get(url string) string {
return r.Contents
}
// package main
type Retriever interface {
Get(url string) string
}
Go 裏面比較噁心的是什麼呢?就是這裏的接口實現,從Java過來的看到這個肯定會比較懵逼。首先必須先生命一點,這裏的 Retriever struct 和 Retriever interface 不是必須取名要一致的,我純粹是爲了 這個 struct 要去實現 interface , 然後取名一樣的話,我知道我這個 struct 實現的是什麼 interface , 這裏的 interface 你可以換個名字,比如這樣看:
// package mooc
type Retriever struct {
Contents string
}
func (r Retriever) Get(url string) string {
return r.Contents
}
// package main
type InterfaceRetriever interface {
Get(url string) string
}
現在你能看出來 Retriever struct 實現的是哪個 interface 嗎?看不出來的好吧?你要是覺得,實現的就是這個 InterfaceRetriever , 雖然的確是實現的是他,但是我們不能猜,我在改一下:
type Retriever interface {
Get(url string) string
}
type InterfaceRetriever interface {
Get(url string) string
}
現在你覺得,他實現的是哪一個?是不是看不出來?這怎麼可能看的出來實現的是哪一個呢?這就是我覺得 GO 裏面比較噁心的地方之一。我們現在來看一下,編輯器爲我們的引導:
Retriever interface:
InterfaceRetriever interface:
Retriever struct:
現在可以看到了,兩個interface 之間互通,Retriever struct 也是腳踏兩隻船。
可是如果這麼改之後:
這個時候,InterfaceRetriever interface 實現的是 Retriever interface 接口, Retriever struct 也是實現 Retriever interface 接口。這樣,就能說明問題了。 Go 裏面的接口實現看你實現的是那個方法裏面接口,而且是全部實現纔算你實現了接口,而且這裏面的優先原則是誰先被實現完,誰就是誰爸爸。
var r Retriever
r = mooc.Retriever{
Contents: "this is mock interface",
}
fmt.Printf("%T %v \n" , r ,r)
switch retriever := r.(type){
case mooc.Retriever:
fmt.Println("mooc Retriever: " , retriever.Contents)
}
從這裏可以看到,在接口 Retriever 裏面, 也就是這裏的 r 裏面,是包含這個 接口類型和值的。
- 接口變量自帶指針
- 接口變量同樣採用值傳遞,幾乎不需要使用接口的指針
- 指針接收者實現只能以指針方式使用;值接收者都可以