想要理解interface,需先要理解【类型元数据】
老规矩,直接上图
一、类型元数据
二、类型元数据结构体 runtime._type 概况
三、空接口
四、非空接口
五、itab缓存复用
六、接口类型断言
接口类型断言四种模式:空接口 || 非空接口.(具体类型 || 非空接口)
下面只讨论理论,不讨论过程,itab指针缓存暂不考虑
1. 空接口.(具体类型) 判断 e 的动态类型是否为具体类型
var e interface{}
f, _ := os.Open("/a.txt")
e = f
r, ok := e.(*os.File)
// 因为 e = f
// 所以 e 的动态类型元数据 为 *os.File 即 _type = *os.File (同时 data = f)
// 断言成功
2.空接口.(非空接口) 判断 e 的动态类型是否实现了 io.ReadWriter 的接口
var e interface{}
f, _ := os.Open("/a.txt")
e = f
r, ok := e.(io.ReadWriter)
// 因为 e = f
// 所以 e 的动态类型元数据 为 *os.File 即 _type = *os.File (同时 data = f)
// 类型元数据 *os.File 实现了 io.ReadWriter 的接口(Read , Writer)
// 断言成功
3.非空接口.(具体类型) 判断 rw 的动态类型是否是 *os.File
var rw io.ReadWriter
f, _ := os.Open("/a.txt")
rw = f
r, ok := rw.(*os.File)
// rw 的接口类型元数据 为 io.ReadWriter 即 tab.inter = io.ReadWriter
// 因为 rw = f
// 所以 rw 的动态类型元数据 为 *os.File 即 tab._type = *os.File (同时 data = f)
// 断言成功
4.非空接口.(非空接口) 判断 w 的动态类型是否实现了 io.ReadWriter 的接口
var w io.Writer
f, _ := os.Open("/a.txt")
w = f
r, ok := w.(io.ReadWriter)
// w 的接口类型元数据 为 io.Writer 即 tab.inter = io.Writer
// 因为 w = f
// 所以 w 的动态类型元数据 为 *os.File 即 tab._type = *os.File (同时 data = f)
// 然后要确认 *os.File 是否实现了 io.ReadWriter 的接口(Read , Writer)
// 断言成功
断言总结:
e 无论空与非空
e.(具体类型) 判断的是 e 的动态类型是否是具体类型,如上述中的 1 和 3
e.(非空接口) 判断的是 e 的动态类型是否实现了非空接口,如上述中的 2 和 4
参考:幼麟实验室
学习整理:马丁之帜