Go語言interface的介紹

Interface 是Go語言里很優(yōu)秀的一個設(shè)計展姐,它本身是僅僅是一個結(jié)構(gòu)體殃饿,但是通過interface我們可以實現(xiàn)面向?qū)ο蟮暮芏嗵匦裕热缍鄳B(tài)息裸、動態(tài)聯(lián)編等。interface 在Go 語言里使用起來的感覺沪编,相比于其它語言也要優(yōu)雅得多呼盆。

底層實現(xiàn)

Interface 的底層只是一個簡單的由c語言實現(xiàn)的數(shù)據(jù)結(jié)構(gòu):

struct Eface
{
    Type*    type;
    void*    data;
};

type 表示它的類型,data 里存儲了它的具體信息蚁廓。對于Go語言访圃,任何數(shù)據(jù)類型都是可以由interface{}來表示的。當我們使用時可以通過反射把里面的信息取出來相嵌。

方法實現(xiàn)

我們先定義一個簡單的接口腿时,類似于Java 中的那樣。

type Animal interface {
    Run()
    Roar()
}

定義一個結(jié)構(gòu)體 Dog 饭宾,直接定義Run 和 Roar 方法批糟,即可實現(xiàn)接口。

type Dog struct {
    Name string
    Size string
}

func (d *Dog)Run()  {
    fmt.Printf("Dog %s run!\n", d.Name)
}

func (d *Dog)Roar()  {
    fmt.Printf("A %s dog roar!\n", d.Size)
}

聲明一個Dog 類型并初始化看铆。

func main () {
    d := Dog{
            Name: "Jim",
            Size: "big",
        }
    d.Run()
    d.Roar()
}
// output: 
//      Dog Jim run!
//      A big dog roar!

這樣實現(xiàn)一個接口的方法很簡單徽鼎,只需要在定義某一類型的時候,定義一個同名的方法即可。

多態(tài)

我們可以直接聲明一個該接口的變量否淤,再讓這個變量指向?qū)崿F(xiàn)其方法類型的實例的地址悄但,這個變量就可以調(diào)用此實例的方法。

func main() {
    ...
    var a Animal
    a = &d
    a.Run()
    a.Roar()
}
// output:
//      Dog Jim run!
//      A big dog roar!

同樣定義另外一個實現(xiàn)該接口的類型石抡。

type Cat struct {
    Name string
    Color string
}

func (c *Cat)Run()  {
    fmt.Printf("Cat %s run!\n", c.Name)
}

func (c *Cat)Roar()  {
    fmt.Printf("A %s cat roar!\n", c.Color)
}

再讓上面聲明的接口變量指向這個類型的實例的地址檐嚣,實際上調(diào)用方法的對象則變成后者。

func main() {
    ...
    c := Cat{
        Name: "Kitty",
        Color: "yello",
    }
    a = &c
    c.Roar()
    c.Run()
}
//output:
//      A yello cat roar!
//      Cat Kitty run!

Go語言里面向?qū)ο蟮奶匦酝ㄟ^interface 很輕易地體現(xiàn)了出來汁雷。本質(zhì)上上述聲明的Animal 變量a 是一個指針净嘀,它底層的內(nèi)存結(jié)構(gòu)包含兩個字段:

  • receiver,a可以指向任意變量侠讯,只需要這個變量的類型實現(xiàn)了該接口挖藏,此時receiver 存儲該變量的地址,實際上此地址指向的其實是該變量的一個副本厢漩,因為Go 會在堆上申請一段空間用以存儲變量的副本膜眠。如果該變量不大于一個字,則該變量直接存儲在receiver 中溜嗜。
  • method table ptr宵膨,類似于C++ 里的虛函數(shù)表,當a 指向某實例變量后炸宵,該字段存儲其方法的入口地址辟躏。

類型轉(zhuǎn)換

一個空的 interface ,不包含任何方法土全,因此它能夠存儲任意類型的值捎琐。

func main() {
    var i interface{}
    a := 1
    i = a
    fmt.Println(i)
    b := true
    i = b
    fmt.Println(i)
}
//output:
//      1
//      true

我們可以借此實現(xiàn)一個函數(shù),它的參數(shù)可以接收任意類型的值裹匙。這時瑞凑,interface 的用法就比較像Java里的Object 對象。同樣概页,我們使用這個參數(shù)前需要類型轉(zhuǎn)換籽御,在Java里可以通過運算符instanceof 來判斷一個對象的實例是否為某一類型,并可以通過顯示類型轉(zhuǎn)換來使用這個實例惰匙。 在Go語言里技掏,我們通過斷言一樣可以做到這些。先看看斷言的用法:

func testFunc(animal interface{})  {
    if c, ok := animal.(Cat); ok {
        fmt.Println(c)
    } else {
            fmt.println("It's not a cat!")
    }
}

格式為:變量名.(類型名)项鬼。返回兩個值零截,第一個值為轉(zhuǎn)換類型后的實例,第二個值為布爾變量秃臣,如果傳入的參數(shù)為Cat 類型就返回 true, 否則返回 false 。 調(diào)用testFunc 時,在函數(shù)里判斷其傳入的參數(shù)是否為Cat 類型奥此,如果是就打印出它的值弧哎。

也可以直接使用斷言返回的第一個值。用法如c := animal.(Cat)稚虎,直接忽略判斷的結(jié)果撤嫩。下面我們?yōu)閠estFunc 加入更多類型的判斷,這時蠢终,通過結(jié)合switch的使用序攘,使代碼可讀性更加友好。

func testFunc(animal interface{})  {
    switch animal.(type) {
    case Dog:
        fmt.Println(animal)
    case Cat:
        fmt.Println(animal)
    default:
        fmt.Println("It's nothing!")
    }
}

個人博客 http://witchiman.github.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寻拂,一起剝皮案震驚了整個濱河市程奠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祭钉,老刑警劉巖瞄沙,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慌核,居然都是意外死亡距境,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門垮卓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垫桂,“玉大人,你說我怎么就攤上這事粟按∥芴玻” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵钾怔,是天一觀的道長碱呼。 經(jīng)常有香客問我,道長宗侦,這世上最難降的妖魔是什么愚臀? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮矾利,結(jié)果婚禮上姑裂,老公的妹妹穿的比我還像新娘。我一直安慰自己男旗,他們只是感情好舶斧,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著察皇,像睡著了一般茴厉。 火紅的嫁衣襯著肌膚如雪泽台。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天矾缓,我揣著相機與錄音怀酷,去河邊找鬼。 笑死嗜闻,一個胖子當著我的面吹牛蜕依,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琉雳,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼样眠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翠肘?” 一聲冷哼從身側(cè)響起檐束,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锯茄,沒想到半個月后厢塘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡肌幽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年晚碾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喂急。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡格嘁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出廊移,到底是詐尸還是另有隱情糕簿,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布狡孔,位于F島的核電站懂诗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏苗膝。R本人自食惡果不足惜殃恒,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辱揭。 院中可真熱鬧离唐,春花似錦、人聲如沸问窃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽域庇。三九已至嵌戈,卻和暖如春覆积,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咕别。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工技健, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惰拱。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像啊送,于是被迫代替她去往敵國和親偿短。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理馋没,服務(wù)發(fā)現(xiàn)昔逗,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法篷朵,類相關(guān)的語法勾怒,內(nèi)部類的語法,繼承相關(guān)的語法声旺,異常的語法笔链,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 官方網(wǎng)站:https://golang.org/標準庫文檔:https://golang.org/pkg/在線編碼...
    技術(shù)學(xué)習閱讀 2,326評論 2 39
  • 似有絲縷掠過 無若這般恍惚 癱倒的路邊草叢 靜謐的 依偎在風伏與曠野 輕柔的吹拂 游過旅人走過的路 燈火撲朔 又迷...
    ___零點閱讀 313評論 0 7
  • 第四章:求無上覺 先斷輪回 --佛答金剛藏菩薩問 于是金剛藏菩薩在大眾中,即從座起腮猖,頂禮佛足鉴扫,右繞三匝,長跪叉手澈缺。...
    可風0576閱讀 224評論 0 0