【知识碎片】
- 接口实现:类型
A的方法集合是接口I的超集,A类型就实现了I接口;所有类型都实现了空接口类型interface{}。 - 接口方法名需具名,其他参数列表类型、返回值类型不用具名,但多个接口嵌入时,方法名如果相同,那么函数签名也必须一样,不能出现类似java 重载的用法。
- 可以用非导出方法。
- 实现接口的类型,可以作为该接口类型变量的右值,(泛型之外的具有“泛型”能力的语法元素)
- 类型断言 comma, ok 和普通:= 结果的区别。
- 接口的实现,不是显示的 而是通过实现方法 隐式的将类型实现接口
接口类型 在Go运行时的表示
静态特性
接口类型变量的静态类型体现了接口的静态特性,在运行时接口变量右值的真实类型就是接口的动态类型(类似java “多态” ,用父类的类型声明变量可实例化子类的类型)
动态特性
接口类型变量内部表示
// $GOROOT/src/runtime/runtime2.go
//非空接口类型
type iface struct {
tab *itab
data unsafe.Pointer
}
// $GOROOT/src/runtime/runtime2.go
type itab struct {
inter *interfacetype
_type *_type // 同空接口中的_type一样
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.
}
//空接口
type eface struct {
_type *_type
data unsafe.Pointer
}
判断接口变量是否相等
- _type (空接口就是 tab._type)
- data所指想内存空间中的值,不是判断data本身
所以接口类型变量的nil _type是有实际地址的 ,nil 的type是0x0,nil也是类型,所有类型都是实现了interface{} 所以都有(_type,data)
go 语言每种类型都有 _type信息
// $GOROOT/src/runtime/print.go
func printeface(e eface) {
print("(", e._type, ",", e.data, ")")
}
func printiface(i iface) {
print("(", i.tab, ",", i.data, ")")
}
非空接口和空接口类型变量比较
虽然静态类型不同,但动态类型的同类接口类型变量的 _type/tab 信息是相同的,所以才可以出现相等的情况
var eif interface{} = T(5)
var err error = T(5)
接口类型的装箱(boxing)原理
装箱后,原变量就和赋值后的接口变量类型没有关系了。 装箱实际上就是 创建_type和data 并创建相关内存,拷贝数据。