54.蛤蟆筆記go語言——interface使用

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

54.蛤蟆筆記go語言——interface使用

         Go語言中使用interface是比較困難的。使用基本比較簡單,但是設計自己的interface就比較困難了。所以如何高效使用interface很有必要。

什麼是interface

         一個interface包含兩個東西:一組方法(也是類型),或類型。

         例如一個animal 類型可以是一個介面。可以定義animal為任何可以說話的。

type Animal interface {

    Speak() string

}

         這樣定義了animal,可以是任何包含speak方法的類型。

         Speak沒有任何參數,返回一個字串。任何定義了該方法的類型都滿足animal介面。

         沒有關鍵字來指定類型是否滿足介面,這個是自動實現的。建立一對類型來滿足這個介面。

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!"

}

這樣有4個類型的animals:一個狗、一個貓、一個llama和一個java程式員。

主函數如下:

func main() {

    animals :=[]Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}

    for _, animal:= range animals {

       fmt.Println(animal.Speak())

    }

}

運行如下:

Woof!

Meow!

?????

Designpatterns!

Interface{}類型

Interface{}類型是空的介面。很多疑惑的根源。

空的介面沒有方法。因為沒有implemets關鍵字,所以至少有0個方法的類型都自動滿足空介面。PS:是至少有0個,呵呵,就是任何時候都成立了哦。

         意味著,如果寫了一個函數將interface{}作為介面,那麼這個函數可以接受任何值

如下函數:

func DoSomething(v interface{}) {

   // ...

}

接受任何參數。

         那麼問題來了,在函數體中v是什麼類型呢?是不是任何類型呢?這是不對的,v不是任何類型,而是interface{}類型。任何值在運行時候都有確定的類型,v就是interface{}類型。

         其實一個interface{}值儲存的2個資料位元組。一個用於指向類型的方法表,另一個指向這個值實際儲存的資料。如果理解interface值是2個位元組包含指標指向資料,就會避免很多陷阱。對於interface介面的實現,可以參考後面的友情連結。

         在上一個例子中構建animal類型的slice,不需要使用Animal(Dog{})說明Dog類型,在animal的slice中,每個元素都是animal類型,但是不同的值有不同的類型。

         不知道interface如何在記憶體中儲存的確會迷惑。例如,可以將[]T轉換成[]interface{}嗎?

         如果知道interface如何儲存就很容易理解了。

代碼

package main

 

import (

    "fmt"

)

 

func PrintAll(vals[]interface{}) {

    for _, val := range vals {

        fmt.Println(val)

    }

}

 

func main() {

    names := []string{"stanley","david", "oscar"}

    PrintAll(names)

}

運行報錯如下:

cannotuse names (type []string) as type []interface {} in argument to PrintAll

不能把[]string轉換為[]interface.

如果想要工作,需要將[]string轉換為[]interface{}

如下:

packagemain

 

import(

    "fmt"

)

 

funcPrintAll(vals[]interface{}){

    for_,val:=rangevals{

        fmt.Println(val)

    }

}

 

funcmain(){

    names:=[]string{"stanley","david","oscar"}

    vals:=make([]interface{},len(names))

    fori,v:=rangenames{

        vals[i]=v

    }

    PrintAll(vals)

}

執行如下:

stanley

david

oscar

這個的確不是很完美,但是實際上[]interface{}很少使用。

指標和介面

另一個介面的細節是介面定義。定義沒有描述是否使用指標接受還是值接受來實現介面。當給出的是一個介面值,不能保證類型是不是一個指標。在之前的例子中,定義所有的方法是值接收,賦值給animal的sclie. 我們來改變一下貓的Speak()方法為指標接收如下:

func (c *Cat) Speak() string {

    return "Meow!"

}

如果允許就會報錯如下:

cannot use Cat literal (typeCat) as type Animal in array or slice literal:

Catdoes not implement Animal (Speak method has pointer receiver)

可以通過將*Cat指標指向animal slice來替代 Cat值。還用new(Cat)來代替Cat{}

如:

animals := []Animal{Dog{}, new(Cat), Llama{},JavaProgrammer{}}

         OK,繼續。

         傳遞*Dog指標代替Dog值,但是不改變Dog的Speak函數。

如下:

animals := []Animal{new(Dog), new(Cat), Llama{},JavaProgrammer{}}

也可以正常工作。但是小許不同的是,不需要改變Speak方法的接收類型。這是因為指標類型可以方法相關的方法,但是反過來是不可以的。*Dog可以使用Speak方法,但是一個Cat不能訪問*Cat的Speak.

         我們要切記的是: Go中傳遞的任何東西都是值。每次你調用一個函數,會傳遞資料的副本。

func (t T)MyMethod(s string) {

    // ...

}

函數類型是func(T,string),函數值通過值來傳遞。

在方法定義的接收器實值型別的改變不會被調用者看見,因為調用者是看見完整隔離的Dog值。

         既然所有東西都是通過值來傳遞,那麼明顯*Cat方法不能被cat值使用,任何Cat值可能有任何的*Cat指標來指向。如果想通過使用Cat值來調用一個*Cat方法,不能使用*Cat指標開始。相反,如果有一個基於Dog類型的方法,我們有一個*Dog指標,通過*Dog指標可以明確指向一個Dog值,那麼Go runtime會在需要的時候將指標關聯到Dog值。所以,給出一個*Dog值,和一個Dog類型的方法,就可以調用Dog的方法。

友情連結

http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go

http://www.laktek.com/2012/02/13/learning-go-interfaces-reflections/

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.