Go語言接口——interface

Go語言的Interface接口是一種神奇的特性。Interface包括了一組方法,同時(shí)也是一種類型。Interface支持"鴨子類型"(Duck
Typing),只要能做所有鴨子能做的事,就認(rèn)為它是個(gè)鴨子;只要實(shí)現(xiàn)了接口的所有方法,就是這個(gè)Interface的類型。

type Animal interface {
    Speak() string
}

type Dog struct {
}

func (d Dog) Speak() string {
    return "Woof!"
}

type Cat struct {
}

func (c Cat) Speak() string {
    return "Meow!"
}

type Llama struct {
}

func (l Llama) Speak() string {
    return "?????"
}

type JavaProgrammer struct {
}

func (j JavaProgrammer) Speak() string {
    return "Design patterns!"
}

func main() {
    animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
    for _, animal := range animals {
        fmt.Println(animal.Speak())
    }
}
1. 空接口 interface{}

interface{}作為類型時(shí)可以看做是一個(gè)實(shí)現(xiàn)了0個(gè)方法的匿名接口,任何類型都至少實(shí)現(xiàn)了0個(gè)方法,因此任何類型都可以實(shí)現(xiàn)了interface{}接口。有這樣一個(gè)有趣的錯(cuò)誤的例子。

// 這是錯(cuò)誤的
package main

import (
    "fmt"
)

func PrintAll(vals []interface{}) {
    for _, val := range vals {
        fmt.Println(val)
    }
}

func main() {
    names := []string{"stanley", "david", "oscar"}
    PrintAll(names)
}

因?yàn)閇]interface{}類型是一種普通類型,即元素為interface{}的切片類型,而不是一個(gè)接口。如果要轉(zhuǎn)換的話,需要對每個(gè)元素進(jìn)行類型轉(zhuǎn)換,代碼如下:

package main

import (
    "fmt"
)

func PrintAll(vals []interface{}) {
    for _, val := range vals {
        fmt.Println(val)
    }
}

func main() {
    names := []string{"stanley", "david", "oscar"}
    vals := make([]interface{}, len(names))
    for i, v := range names {
        vals[i] = v
    }
    PrintAll(vals)
}
2. 接口和指針

如果第一個(gè)例子的Cat的speak方法做一個(gè)改成如下的代碼:

func (c *Cat) Speak() string {
    return "Meow!"
}

再運(yùn)行程序就會報(bào)錯(cuò)。
在go語言中,如果是指針作為receiver,當(dāng)使用值作為該接口的實(shí)例調(diào)用會出現(xiàn)編譯錯(cuò)。而相反的,使用值作為receiver,使用指針作為接口實(shí)例調(diào)用沒有問題。

為什么呢?
因?yàn)橥ㄟ^一個(gè)指針,就可以訪問這個(gè)類型作為receiver的所有方法。但是返回來,給你一個(gè)值,卻不能訪問這個(gè)值的指針類型的方法。
在進(jìn)一步解釋就是: Go語言的所有傳遞都是值傳遞的。在將Cat轉(zhuǎn)換為Animal的Interface的時(shí)候,傳遞的是Cat的值拷貝,取不到原來的指針,此時(shí)取指針的話,取到的就不是原來的Cat的指針,就失去了以指針作為reciever的意義了。而反過來,通過一個(gè)指針的值,可以找到唯一的一個(gè)Cat對象,所以是可以轉(zhuǎn)換的。
如果了解了,go語言如何實(shí)現(xiàn)interface的,interface的數(shù)據(jù)結(jié)構(gòu)分為兩個(gè)部分:類型和方法列表,原來的數(shù)據(jù)本身。就更好理解了。

3. 接口的類型轉(zhuǎn)換

見我的另一篇《Go語言類型轉(zhuǎn)換和類型斷言》http://www.itdecent.cn/p/bd2acab2a8e9

4. Embedding(嵌入)

Go中沒有繼承的概念,用Embedding來取代,實(shí)現(xiàn)方式為接口的匿名成員。
見《Go匿名成員》 http://www.itdecent.cn/p/76eac0b8d563

參考:

  1. http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
  2. https://research.swtch.com/interfaces
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容