結合源碼理解interface{}

來源:互聯網
上載者:User

首先要明確go中的interface分為兩種,無方法聲明和有方法聲明的的,對應源碼中的定義如下:

//有方法聲明type iface struct {    tab  *itab    data unsafe.Pointer}//無方法聲明type eface struct {    _type *_type    data  unsafe.Pointer}

其中data指向實際的值資訊,_type是對定義內部類型資訊的資料結構,itab裡定義了介面相關資訊,包括介面類型、實際類型、實現的方法集等:

type itab struct {    inter  *interfacetype    _type  *_type    link   *itab    hash   uint32 // copy of _type.hash. Used for type switches.    bad    bool   // type does not implement interface    inhash bool   // has this itab been added to hash?    unused [2]byte    fun    [1]uintptr // variable sized}

interfacetype是關於一個介面本身的資訊,包括這個介面的類型、包含的方法集以及包名等。
iface則對應的是把一個struct轉為interface後的資訊。
fun中存放了interfacetype需要的方法集的具體實現,因為方法記憶體中是順序存放的,所以fun中只需要儲存第一個方法地址的指標。

hashSize = 1009hash      [hashSize]*itab

可能是為了效能考慮,所有的itab實際是存放在一個全域hash表中,當把一種interface類型轉為另一種interface類型時,調用的源碼是:

func convI2I(inter *interfacetype, i iface) (r iface) {    tab := i.tab    if tab == nil {        return    }    if tab.inter == inter {        r.tab = tab        r.data = i.data        return    }    r.tab = getitab(inter, tab._type, false)    r.data = i.data    return}

可以看到當i中tab的inter和要轉的inter相同時,直接就可以轉換,否則要調用getitab擷取待轉r的itab。

func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {...    h := itabhash(inter, typ)    var m *itab    var locked int    for locked = 0; locked < 2; locked++ {        if locked != 0 {            lock(&ifaceLock)        }        for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {          if m.inter == inter && m._type == typ {...            return m          }        }    m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))    m.inter = inter    m._type = typ    additab(m, true, canfail)    unlock(&ifaceLock)    if m.bad {        return nil    }    return m

上面的代碼,首先是用inter和typ計算一個hash值,然後看全域itab的hash表中是否含有這個hash值的itab,如果有並且這個itab的inter和typ符合條件,則證明之前已經有過類似轉換,符合類型轉換條件。如果沒有,再試圖調用additab:

func additab(m *itab, locked, canfail bool) {    inter := m.inter    typ := m._type    ...    h := itabhash(inter, typ)    m.link = hash[h]    m.inhash = true    atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))}

省略符號的部分是判斷m的typ是否實現了inter方法集的邏輯,如果沒有全部實現,證明類型轉換不合法m.bad會被置為true。如果轉換合法,最後會把m存入全域itab hash表中。

參考文章:

  • http://legendtkl.com/2017/07/01/golang-interface-implement/
  • https://www.tapirgames.com/blog/golang-interface-implementation
相關文章

聯繫我們

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