golang的struct里面嵌入interface

golang的struct里面嵌入interface

先通過(guò)幾個(gè)例子來(lái)說(shuō)明這樣用法。

例子1

定義一個(gè)Interface II包含兩個(gè)函數(shù)聲明

  1. F1()
  2. F2()

然后定義一個(gè)struct SS,它實(shí)現(xiàn)了函數(shù)F1和F2,這樣SS其實(shí)就是II的一個(gè)實(shí)現(xiàn)。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
}

func (ss *SS) F1() {
}

func (ss *SS) F2() {
}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
} 

編譯運(yùn)行,輸出如下

$ go build && ./main
ss:value=[{0}]
ii:value=[&{0}]

例子2

如果在struct SS中不實(shí)現(xiàn)F1和F2,或者只實(shí)現(xiàn)F1或者F2,還能不能繼續(xù)使用呢。
還是前面的代碼,我們注釋掉F2的定義。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
}

func (ss *SS) F1() {
}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
}

編譯運(yùn)行

$ go build && ./main
# testinterfacestruct
./main.go:25: cannot use &ss (type *SS) as type II in assignment:
        *SS does not implement II (missing F2 method)

編譯器報(bào)錯(cuò),不能把ss賦值給ii,因?yàn)镾S不是II的實(shí)現(xiàn)。

例子3

那么如何解決上述問(wèn)題呢,嵌入interface的作用就出來(lái)了。我們把interface作為struct的一個(gè)匿名成員,就可以假設(shè)struct就是此成員interface的一個(gè)實(shí)現(xiàn),而不管struct是否已經(jīng)實(shí)現(xiàn)interface所定義的函數(shù)。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
}

//func (ss *SS) F1() {
//}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
}

這個(gè)例子中,struct SS沒(méi)有實(shí)現(xiàn)interface II的任何一個(gè)函數(shù),只是在聲明struct的時(shí)候把II作為一個(gè)匿名成員,此時(shí) var ii II = &ss 賦值語(yǔ)句沒(méi)有任何錯(cuò)誤,可見(jiàn)ss已經(jīng)被認(rèn)為是interface II的實(shí)現(xiàn)。

所以嵌入interface可以使得一個(gè)struct具有interface的接口,而不需要實(shí)現(xiàn)interface中的有聲明的函數(shù)。

例子4

既然沒(méi)有實(shí)現(xiàn)函數(shù),那么如何調(diào)用接口的呢?答案是,沒(méi)有實(shí)現(xiàn)肯定是不能調(diào)用啊,直接crash了;只能調(diào)用已經(jīng)實(shí)現(xiàn)的函數(shù)。
還是在上述例子中,我們定義F1,沒(méi)有實(shí)現(xiàn)F2,那么可以正常調(diào)用F1,但是不能調(diào)用F2

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
}

func (ss *SS) F1() {
    fmt.Printf("in SS::F1()\n")
}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)

    ii.F1()
}

運(yùn)行結(jié)果

ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
in SS::F1()

如果我們運(yùn)行F2呢,會(huì)出什么結(jié)果?

把main函數(shù)改成試試:

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)

    // ii.F1()
    ii.F2()
}

編譯運(yùn)行:

$ go build && ./main
ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x47d680]

goroutine 1 [running]:
main.(*SS).F2(0xc42000a300)
        <autogenerated>:3 +0x40
main.main()
        /home/.../go/src/main/main.go:33 +0x185

可見(jiàn)編譯器成功完成了編譯,但是在運(yùn)行的時(shí)候出錯(cuò)了,因?yàn)镕2函數(shù)根本找不到。

例子5

我們分析一個(gè)嵌入Interface的實(shí)現(xiàn);在前面我們已經(jīng)看到struct和interface的內(nèi)容了。

ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]

ss的內(nèi)容包含一個(gè)0值和一個(gè)nil值,0值vv的值,那么<nil>推測(cè)就是II的值了;增強(qiáng)一下代碼:

package main

import (
    "fmt"
    "unsafe"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
    ww int
}

func (ss *SS) F1() {
    fmt.Printf("in SS::F1()\n")
}

func (ss *SS) F2() {
    fmt.Printf("in SS::F2()\n")
}

func main() {
    var ss SS = SS{vv:1,ww:2}
    var ii II = &ss

    fmt.Printf("ss:size=[%d],value=[%v]\n", unsafe.Sizeof(ss), ss)
    fmt.Printf("ii:size=[%d],value=[%v]\n", unsafe.Sizeof(ii), ii)
}

運(yùn)行結(jié)果:

$ go build && ./main
ss:size=[32],value=[{1 <nil> 2}]
ii:size=[16],value=[&{1 <nil> 2}]

可見(jiàn)ss占用32字節(jié),前8字節(jié)和后8字節(jié)分別是變量vv和ww,中間的16字節(jié)必須是給II的;這是一個(gè)占位符,沒(méi)有具體的值,其值為nil。

這個(gè)地方有疑問(wèn),為什么是一個(gè)nil的占位符。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容