从多个问题动身,浅谈Go interface
〇、前言
这是《让咱们一起Golang》专栏的第46篇文章,本文从多个问题浅谈Go的接口interface,不过由于笔者水平和工作经验限制,或许文章存在许多缺乏或过错,烦请指出斧正!
本专栏的其他文章:
-
深化了解 Golang map 规划理念与完成原理 –
-
云青青兮欲雨——Go的数组与切片傻傻分不清楚? –
-
安得倚天抽宝剑——Go中new到底在堆仍是栈中分配 –
-
从源码分析视点浅谈Golang Channel –
-
…
一、Go言语“折中”的做法与传统静态言语、动态言语
静态言语是在编译时就会查看类型不匹配的过错,而动态言语需要程序运行到那一行才干知道类型的问题。而Go言语作为一门比较“年轻”的静态言语,既保留了静态言语的类型查看长处,有引入了动态言语的长处。它采用了一种“折中”的做法:完成接口时并不要求指定是哪个类型完成的,只需完成接口的某个办法编译器就能够检测到。
看下面这段代码:
type Human interface {
eat()
sleep()
}
type man struct {
name string
age int
}
type woman struct {
name string
age int
}
func (m *man) eat() {
fmt.Println("a man is eating")
}
func (w *woman) eat() {
fmt.Println("a woman is eating")
}
func (m *man) sleep() {
fmt.Println("a man is sleeping")
}
func (w *woman) sleep() {
fmt.Println("a woman is sleeping")
}
func main() {
bob := man{
name: "bob",
age: 18,
}
lily := woman{
name: "lily",
age: 20,
}
bob.eat()
lily.eat()
bob.sleep()
lily.sleep()
}
是不是没有发现那些办法显式的完成了接口,可是Goland已经帮咱们把它们的联系标示出来了,编译器能够检测到它们之间的联系。
当编译器在调用eat()、sleep()时,会将man、woman对象转换成human类型,实际上这也是一种类型查看。
二、接口的底层完成iface和eface
iface和eface都为Go中接口的底层结构体,它们的区别是iface表明的接口类型变量包括办法,而eface表明的接口是不包括任何办法的空接口。
// $GOROOT/src/runtime/runtime2.go
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}
2.1 iface
能够看到iface包括两个指针tab
以及data
。
tab用来存储接口自身的信息(如接口类型等),还存储赋给这个接口的详细类型。
data则指向当时被赋给接口类型变量的详细的值。
在来看一下tab字段的类型itab:
// $GOROOT/src/runtime/runtime2.go
type itab struct {
inter *interfacetype
_type *_type
link *itab
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
itab的inter字段描述了接口自身的信息,type被用来描述实体的类型,hash是实体类型type的哈希,用于类型转换,fun用来存储实体类型完成接口办法的调用地址。
有人会疑问了,为什么fun的大小为1,这样是不是代表只能接口只能界说一个办法。其实不是的,一个接口能够界说多个办法,此处存储的时第一个办法的函数指针,若有其他办法,会放在这以后的内存空间之中,由于函数指针的大小是固定的,因此经过增加地址值即可找到接口的下一个函数指针方位。
别的看一看interfacetype
结构体:
// $GOROOT/src/runtime/runtime2.go
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
包括了接口类型typ
, 接口的包路径名pkgpath
和用来存储接口办法函数集的切片mhdr
。
2.2 eface
和iface比较,eface就比较简单了,其界说如下:
// $GOROOT/src/runtime/runtime2.go
type eface struct {
_type *_type
data unsafe.Pointer
}
和iface一样,_type
表明详细类型的类型信息,data执行详细类型变量的值。
参考文献
了解Go interface的两种底层完成:iface和eface blog.frognew.com/2018/11/go-…
Interfaces in Go -Go 101 go101.org/article/int…
Go 言语与鸭子类型的联系 golang.design/go-question…
本文正在参加「金石计划 . 分割6万现金大奖」