什么是 interface
Go 语言中的接口声明:
type Human interface {
Say(s string) error
}
关键字主体为 type xxx interface,紧接着可以在方括号中编写方法集,用于声明和定义该接口所包含的方法集。
举个例子:
type Human interface {
Say(s string) error
}
type TestA string
func (t TestA) Say(s string) error {
fmt.Printf("煎鱼:%s\n", s)
return nil
}
func main() {
var h Human
var t TestA
_ = t.Say("炸鸡翅")
h = t
_ = h.Say("烤羊排")
}
我们在上述代码中,声明了一个名为 Human 的 interface,其包含一个 Say 方法。同时我们声明了一个 TestA 类型,也有自己的一个 Say 方法。他们两者的方法入参和出参类型均为一样。
而与此同时,我们在主函数 main 中通过声明和赋值,成功将类型为 TestA 的变量 t 赋给了类型为 Human 的变量 h,也就是说两者只因有了个 Say 方法,在 Go 语言的编译器中就认为他们是 “一样” 的了,这也就是业界中常说的鸭子类型。
数据结构
通过上面的功能代码一看,似乎 Go 语言非常优秀。一个接口,不同的类型,2 个包含相同的方法,也能够对标到一起。
接口到底是怎么实现的呢?底层数据结构又是什么?带着问题,我们开始深挖细节之路。
在 Go 语言中,接口的底层数据结构在运行时一共分为两类结构体(struct),分别是:
runtime.eface结构体:表示不包含任何方法的空接口,也称为 empty interface。runtime.iface结构体:表示包含方法的接口。