golang interface理解

最早對interface的認知比較片面,很多人都說interface與channel是go語言的靈魂。然而在工作中使用的機會比較少,發現自己對interface的理解太片面。下面就記錄並總結下go中的interface。

interface是個啥

go程序設計中是這樣解釋的“接口是一種抽象類型,他並沒有暴露所包含數據的佈局或者內部結構,當然也沒有那些數據的基本操作,它所提供的僅僅是一些方法而已”。根據上面的說明我們可以提煉出接口是對一些方法的封裝
很多的C++程序員吐槽go不便之處就是沒有’泛型’我們沒法使用模板啊,go語言中確實沒有,但是go提供了interface讓我們可以實現這種泛型。正如上面所說interface是一種抽象類型,是一組方法的集合,我們可以把它看成一種定義內部方法的動態數據類型,任意實現了這些方法的數據類型都可以認爲是特定的數據類型。(是不是有點像是C++中模板類)。
正如sort包中

package sort

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

在sort包中提供了三個方法,只要我們實現了這三個方法我們就可以對任何的類型進行排序。
看過了官方的sort是如何寫的我們也自己動手寫一個例子

package main

import "fmt"

type classmate struct {
    class uint32
    grade uint32
    age   uint32
    name  string
}

type info interface {
    Len() int
    Compare(agex,agei uint32)uint32
}

type listInfo []classmate
type listuint []uint32

func (this listInfo)Len()(int){
    return len(this)
}

func (this listInfo)Compare(i,j uint32)(uint32){
    if this[i].grade > this[j].grade{
        return this[i].grade
    }
    return this[j].grade
}

func (this listuint)Len()(int){
    return len(this)
}

func (this listuint)Compare(i,j uint32)(uint32){
    if this[i] > this[j]{
        return this[i]
    }
    return this[j]
}


func main(){
    lInfo := listInfo{
        classmate{1,1,6,"tom"},
        classmate{2,3,8,"jim"},
    }
    fmt.Println("len is ", lInfo.Len())
    garde := lInfo.Compare(0,1)
    fmt.Printf("grade is %d \n",garde)

    uInfo := listuint{9,6,8}
    fmt.Println("len is ", uInfo.Len())
    fmt.Printf("compare is %d ",uInfo.Compare(1,2))
}

示例中我們的interface中包含了兩個方法,len與compare,獲取長度與比較大小,我們分別爲不同的類型實現了接口中的方法,是不是有點像C++中的函數重載(C++中函數重載要求參數個數或者參數類型不同)。同時我們也發現我們爲不同的類型實現了方法,所以說一個接口類型不會去關心到底是什麼數據類型實現了他自身。接口類型的本質就是如果一個數據類型實現了自身的方法集,那麼該接口類型變量就能夠引用該數據類型的值。
在上面我們提到了sort包,我們只要實現了其提供的三個方法就可以對任何類型進行排序,因爲我們實現了它的接口類型。

package main

import "fmt"

type classmate struct {
    class uint32
    grade uint32
    age   uint32
    name  string
}

type classinfo struct {
    total uint32
    grade uint32
}

type info interface {
    coutInfo()
    changeInfo(grade uint32)
}

func (this *classmate)coutInfo(){
    fmt.Println("info is ",this)
}

func (this *classmate)changeInfo(grade uint32){
    this.grade = grade
    fmt.Println("info is ",this)
}

func (this *classinfo)coutInfo(){
    fmt.Println("info is ",this)
}

func (this *classinfo)changeInfo(grade uint32){
    this.grade = grade
    fmt.Println("info is ",this)
}

func interTest(test info,grade uint32){
    test.coutInfo()
    test.changeInfo(grade)
}


func main(){
    mate := &classmate{
        class: 1,
        grade:1,
        age:6,
        name:"jim",
    }
    info := &classinfo{
        total:30,
        grade:5,
    }
    interTest(mate,3)
    interTest(info,8)
}

輸出:

info is  &{1 1 6 jim}
info is  &{1 3 6 jim}
info is  &{30 5}
info is  &{30 8}

相信這個例子可以幫助我們更好的理解函數interTest的第一個輸入參數並沒有要求參數的具體類型,而是一個接口類型。

使用interface的注意事項

  1. 將對象賦值給接口變量時會複製該對象。
  2. 接口使用的是一個名爲itab的結構體存儲的
    type iface struct{
    tab *itab // 類型信息
    data unsafe.Pointer // 實際對象指針
    }
  3. 只有接口變量內部的兩個指針都爲nil的時候,接口才等於nil。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章