golang的struct里面嵌入interface
先通過(guò)幾個(gè)例子來(lái)說(shuō)明這樣用法。
例子1
定義一個(gè)Interface II包含兩個(gè)函數(shù)聲明
- F1()
- 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的占位符。