理解go中interface關鍵點

來源:互聯網
上載者:User

interface是golang中的精華所在,本文主要理解interface中的幾個關鍵點。

I、interface即是method的集合,也是一種類型

1、interface存在的基本作用就是其定義了一組方法。
我們之所以又說interface是一種類型,可以從三點來理解:首先從其定義形式中的type關鍵字就可以看出來。另外,函數的形參可以為interface型;最後,interface支撐了go中的多態性,也就是其他類型如果實現了interface中的所有方法,就說類型實現了該interface,這類似於C++中的繼承。

type Inter interface {    Get() int     Set(int)}

2、go中允許不帶任何方法的interface,這種類型稱為empty interface,由於其不帶任何方法,所以可以說所有的類型都實現了empty interface。

II、interface變數儲存的是實作類別型的值

1、由於interface中只存在方法,而方法的形參就來自於其實作類別型。

package main import "fmt"type Inter interface {    Get() int     Set(int)}type St struct {    Age int }func(s St) Get() int {    return s.Age} func(s *St) Set(age int) {    s.Age = age }func test(i Inter) {    i.Set(10)    fmt.Println(i.Get())}func main() {    s := St{}    test(&s)}

這段代碼中,St實現了Inter,執行test(),就完成了對Inter的使用。

2、interface的重要用途之一就是體現在test函數的形參上,如果有多個類型實現了interface,這些類型的值都可以直接使用interface的變數儲存。

s := S{}var i Interi = &sfmt.Println(i.Get())    //會自動調用S中關於Get的實現

這也體現了go中的多態性

III、empty interface

1、空的interface沒有方法,所以所有的類型都實現了empty interface,所以,所有的類型都可以作為empty interface函數的形參:

func doSomething(v interface{}) {}

既然空的interface可以接受任何類型的參數,那麼一個interface{}類型的slice是不是可以接受任何類型的slice呢? --不能!

package main  import "fmt"func printAll(vals []interface{}) {    for _, val := range vals {        fmt.Println(val)    }}func main() {    names := []string{"hello", "world"}    printAll(names)}

執行結果:


這個例子說明go不能將slice轉化成interface{}類型的slice,但是我們可以手動進行轉化:

    var interfaceSlice []interface{} = make([]interface{}, len(names))    for i,d := range names {        interfaceSlice[i] = d    }

執行結果:

IV、receiver的理解

1、go中將定義struct的方法中的func() 中的參數稱為receiver。例如func(s St) Get() int { }中的s就是Get的receiver。要理解他可以聯想C++中的this指標

2、我們在上面的例子中調用test函數是test(&s),也就是St的指標類型,可以是test(s)嗎?

調用test(s)的執行結果如下:

這是一個錯誤的實現,關鍵在於St中Set()方法的receiver是一個pointer *St

interface定義時並沒有規定是閑著的方法receiver是value receiver 還是pointer receiver,如上述例子,當我們使用test(s)的形式調用,傳遞給test的是s的一份拷貝,在進行s的拷貝到Inter的轉換時,s的拷貝不滿速Set()方法的receiver是個pointer,也就是沒有實現。

而如果反過來receiver是value,函數用pointer的形式調用:

package main import "fmt"type Inter interface {    Get() int     Set(int)}type St struct {    Age int }func(s St) Get() int {    return s.Age} func(s St) Set(age int) {    s.Age = age }func test(i Inter) {    i.Set(10)    fmt.Println(i.Get())}func main() {    s := St{}    test(&s)    test(s)}

執行結果為:

之所以沒能按照我們預期的輸出10 10,是因為傳值不能改變未經處理資料的值。但是代碼是能正常啟動並執行,也就是好說receiver都value receiver,執行代碼無論是pointer還是value都可以正常執行。

再思考一下出現這種現象的原因是什麼呢?
如果是傳入pointer,go可以根據pointer找到對應指向的值,但如果是value,傳入的只能是value的拷貝temp,沒辦法根據value的拷貝temp去找到value原始的地址,這就是為什麼pointer可以對應pointer receiver以及value receiver,但value卻無法滿足pointer receiver。

其實這裡很關鍵的一點就是,實參到形參只是一個拷貝。

【參考】
[1] 理解 Go interface 的 5 個關鍵點

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.