interface赋值问题
1 | package main |
多态的几个要素:
1、有interface接口,并且有接口定义的方法。
2、有子类去重写interface的接口。
3、有父类指针指向子类的具体对象
所以上述代码报错的地方在var peo People = Stduent{}
这条语句, Student{}
已经重写了父类People{}
中的Speak(string) string
方法,那么只需要用父类指针指向子类对象即可。
所以应该改成var peo People = &Student{}
即可编译通过。(People为interface类型,就是指针类型)
interface的内部构造(非空接口iface情况)
1 | package main |
结果是: BBBBBB
interface在使用的过程中,共有两种表现形式
一种为空接口(empty interface),定义如下:
1 | var MyInterface interface{} |
另一种为非空接口(non-empty interface), 定义如下:
1 | type MyInterface interface {function()} |
这两种interface类型分别用两种struct
表示,空接口为eface
, 非空接口为iface
.

空接口eface
空接口eface结构,由两个属性构成,一个是类型信息_type,一个是数据信息。其数据结构声明如下:
1 | type eface struct { //空接口 |
_type属性:是GO语言中所有类型的公共描述,Go语言几乎所有的数据结构都可以抽象成 _type,是所有类型的公共描述,**type负责决定data应该如何解释和操作,**type的结构代码如下:
1 | type _type struct { |
data属性: 表示指向具体的实例数据的指针,他是一个unsafe.Pointer
类型,相当于一个C的万能指针void*

非空接口iface
iface 表示 non-empty interface 的数据结构,非空接口初始化的过程就是初始化一个iface类型的结构,其中data
的作用同eface
的相同,这里不再多加描述。
1 | type iface struct { |
iface结构中最重要的是itab结构(结构如下),每一个 itab
都占 32 字节的空间。itab可以理解为pair<interface type, concrete type>
。itab里面包含了interface的一些关键信息,比如method的具体实现。
1 | type itab struct { |
其中值得注意的字段:
interface type
包含了一些关于interface本身的信息,比如package path
,包含的method
。这里的interfacetype是定义interface的一种抽象表示。type
表示具体化的类型,与eface的 type类型相同。hash
字段其实是对_type.hash
的拷贝,它会在interface的实例化时,用于快速判断目标类型和接口中的类型是否一致。另,Go的interface的Duck-typing机制也是依赖这个字段来实现。fun
字段其实是一个动态大小的数组,虽然声明时是固定大小为1,但在使用时会直接通过fun指针获取其中的数据,并且不会检查数组的边界,所以该数组中保存的元素数量是不确定的

1 | func live() People { |
stu是一个指向nil的空指针,但是最后return stu
会触发匿名变量 People = stu
值拷贝动作,所以最后live()
放回给上层的是一个People insterface{}
类型,也就是一个iface struct{}
类型。 stu为nil,只是iface
中的data 为nil而已。 但是iface struct{}
本身并不为nil.

Interface 内部构造(空接口eface情况)
1 | func Foo(x interface{}) { |
结果为 “non-empty interface”
因为 Fool()
的形参 x interface{}
是一个空接口类型eface struct{}
,在执行Foo(p)
的时候,触发x interface{} = p
语句的时候,此X的结构为

所以 x 结构体本身不为nil,而是data指针指向的p为nil
Interface{}与*Interface{}
1 | type S struct { |
结果:
1 | B、D两行错误 |
看到这道题需要第一时间想到的是Golang是强类型语言,interface是所有golang类型的父类 函数中func f(x interface{})
的interface{}
可以支持传入golang的任何类型,包括指针,但是函数func g(x *interface{})
只能接受*interface{}