golang 基礎(29) 接口

square-gopher.png

在 go 語言接口更重視使用者,使用者是否承認和使用接口才是重要的,這里定義 Retriever 接口提供 Get 方法,所有具有 Get 方法的都可以認為是接口

package main

import (
    "fmt"
    "com.zidea/util/mock"
)

type Retriever interface{
    Get(url string) string
}

func download(r Retriever) string {
    return r.Get("www.baidu.com")
}

func main()  {
    var r Retriever
    r = mock.Retriever{"this is fake baidu com"}
    fmt.Println(download(r))
}
func main()  {
    var r Retriever
    r = real.Retriever{}
    fmt.Println(download(r))
}

定義了download方法接受接口Retriever類型的參數,然后調用接口的 Get 方法來獲取網絡資源,那么download無疑就是使用者,只要使用者認為接受參數是Retriever那么就是Retriever,也就是站在使用者角度來審視接口,例如一個需要吃的人認為烤鴨才是他想要的鴨子

20120317151833841.jpg

而一個小朋友認為玩具鴨子才是他想要的鴨子。

接口的值類型

在其他語言中這里 r 可能只是真實的 Retriever 的引用,但是在 go 語言中所有的類型都是值類型,所以 r 還是有內容的。

在 interface 中是有兩個東西類型,這里我們可以通過引用和值形式來實現接口,我們通過打印來看一下接口到底是什么東西,%T 代表類型 %V 代表值,這里分別打印出兩種

r = mock.Retriever{"this is a fake baidu com"}
    fmt.Printf("%T %v\n",r,r) // mock.Retriever {this is a fake baidu com}
r = real.Retriever{}
fmt.Printf("%T %v\n",r,r) // real.Retriever { 0s} // userAgent 是空格, timer 是 0s

我們可以修改為接受者(接口)為引用而非值的形式

r = &real.Retriever{
        UserAgent:"Mozilla/5.0",
        Timeout: time.Minute,
    }
    fmt.Printf("%T %v\n",r,r) // real.Retriever { 0s} // userAgent 是空格, timer 是 0s
func (r *Retriever) Get (url string) string {
    resp, err := http.Get(url)
    if err != nil{
        panic(err)
    }

    result, err := httputil.DumpResponse(
        resp, true)
    resp.Body.Close()
    if err != nil {
        panic(err)
    }

    return string(result)
}
r = &real.Retriever{
        UserAgent:"Mozilla/5.0",
        Timeout: time.Minute,
    }

現在 r 是一個指針,如果是一個真實的值就是 copy,如果

mock.Retriever {this is a fake baidu com}
*real.Retriever &{Mozilla/5.0 1m

既然我們知道接口中有類型,我們怎么知道類型,通過.type 來獲得類型,

func inspect(r Retriever){
    switch v := r.(type) {
    case mock.Retriever:
        fmt.Println("Contents:",v.Contents)
    case *real.Retriever:
        fmt.Println("UserAgent",v.UserAgent)
    }
}

inspect(r)

我們通過 type 就可以知道是什么類型

// Type assertion
    realRetriever := r.(*real.Retriever)
    fmt.Println(realRetriever.Timeout)

通過.獲取r的類型

panic: interface conversion: main.Retriever is mock.Retriever, not *mock.Retriever
if mockRetriever, ok := r.(mock.Retriever); ok{
        fmt.Println(mockRetriever.Contents)
    }else{
        fmt.Println(" not a mock retriever ")
    }

接口變量

  • 實現者的類型
  • 實現者的值(或實現者的指針)

接口變量里面有什么

  • 接口變量自帶指針
  • 接口變量同樣采用值傳遞,幾乎不需要使用接口的指針
  • 指針接收者實現只能以指針方式使用; 值接收都可

查看接口變量

  • 表示任何類型:interface{}
  • Type Assertion
  • Type Switch
package queue

type Queue []int

func (q *Queue) Push(v int) {
    *q = append(*q, v)
}

func (q *Queue) Pop() int {
    head := (*q)[0]
    *q = (*q)[1:]
    return head
}

func (q *Queue) IsEmpty() bool  {
    return len(*q) == 0
}
q := queue.Queue{1}

    q.Push(2)
    q.Push(3)
    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())
golang.jpg

我們這里通過修改這個 queue 類了解一下 interface{} 這個表示任何類型的接口。下面簡單舉個實例看一下 interface{} 接口, interface{} 可以說是無可不能,代替一切類型,同時也就沒有任何意義

type Queue []interface{}

func (q *Queue) Push(v int) {
    *q = append(*q, v)
}

func (q *Queue) Pop() interface{} {
    head := (*q)[0]
    *q = (*q)[1:]
    return head
}

func (q *Queue) IsEmpty() bool  {
    return len(*q) == 0
}
q.Push(2)
    q.Push(3)
    q.Push("abc")
    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())


func (q *Queue) Push(v int) {
    *q = append(*q, v)
}

func (q *Queue) Pop() int {
    head := (*q)[0]
    *q = (*q)[1:]
    return head.(int)
}

這時我們就會在編譯時出現錯誤

.\main.go:55:9: cannot use "abc" (type string) as type int in argument to q.Push
func (q *Queue) Push(v interface{}) {
    *q = append(*q, v.(int))
}

func (q *Queue) Pop() interface{} {
    head := (*q)[0]
    *q = (*q)[1:]
    return head.(int)
}

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容

  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,129評論 1 32
  • 1.安裝 https://studygolang.com/dl 2.使用vscode編輯器安裝go插件 3.go語...
    go含羞草閱讀 1,567評論 0 6
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,872評論 0 38
  • 大師兄同別人曖昧被小公主抓包。 也不是什么新鮮事,有的人就是長相比較風流,對人比較溫柔。 比如我。 我還跟一一閑扯...
    唐四月閱讀 204評論 0 0
  • 從小就愛畫畫,一畫起來,就會忘記了天和地。滿腦子在琢磨著,這里要畫什么?那里要畫什么?這里要涂什么顏色?那里要涂什...
    lin秀閱讀 582評論 4 0