golang的struct里面嵌入interface
先通过几个例子来说明这样用法。
例子1
定义一个Interface II包含两个函数声明
- F1()
- F2()
然后定义一个struct SS,它实现了函数F1和F2,这样SS其实就是II的一个实现。
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)
}
编译运行,输出如下
$ go build && ./main
ss:value=[{0}]
ii:value=[&{0}]
例子2
如果在struct SS中不实现F1和F2,或者只实现F1或者F2,还能不能继续使用呢。
还是前面的代码,我们注释掉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)
}
编译运行
$ 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)
编译器报错,不能把ss赋值给ii,因为SS不是II的实现。
例子3
那么如何解决上述问题呢,嵌入interface的作用就出来了。我们把interface作为struct的一个匿名成员,就可以假设struct就是此成员interface的一个实现,而不管struct是否已经实现interface所定义的函数。
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)
}
这个例子中,struct SS没有实现interface II的任何一个函数,只是在声明struct的时候把II作为一个匿名成员,此时 var ii II = &ss
赋值语句没有任何错误,可见ss已经被认为是interface II的实现。
所以嵌入interface可以使得一个struct具有interface的接口,而不需要实现interface中的有声明的函数。
例子4
既然没有实现函数,那么如何调用接口的呢?答案是,没有实现肯定是不能调用啊,直接crash了;只能调用已经实现的函数。
还是在上述例子中,我们定义F1,没有实现F2,那么可以正常调用F1,但是不能调用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()
}
运行结果
ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
in SS::F1()
如果我们运行F2呢,会出什么结果?
把main函数改成试试:
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()
}
编译运行:
$ 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
可见编译器成功完成了编译,但是在运行的时候出错了,因为F2函数根本找不到。
例子5
我们分析一个嵌入Interface的实现;在前面我们已经看到struct和interface的内容了。
ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
ss的内容包含一个0值和一个nil值,0值vv的值,那么<nil>推测就是II的值了;增强一下代码:
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)
}
运行结果:
$ go build && ./main
ss:size=[32],value=[{1 <nil> 2}]
ii:size=[16],value=[&{1 <nil> 2}]
可见ss占用32字节,前8字节和后8字节分别是变量vv和ww,中间的16字节必须是给II的;这是一个占位符,没有具体的值,其值为nil。
这个地方有疑问,为什么是一个nil的占位符。