在Go语言中,iface和eface是表示接口类型和空接口类型的内部数据结构。
iface表示一个具体的接口类型,包含了指向接口表的指针和指向数据的指针。接口表中存储了该接口类型的方法集信息,数据指针则指向实现了该接口的具体类型的值。
eface则是一个空接口类型,包含了指向类型信息的指针和指向数据的指针。它可以表示任何类型的值。
最大的区别在于 iface 描述的接口包含方法,而 eface 则是不包含任何方法的空接口:interface{}。 从源码层面看一下:
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
iface 内部维护两个指针,tab 指向一个 itab 实体, 它表示接口的类型以及赋给这个接口的实体类型。data 则指向接口具体的值,一般而言是一个指向堆内存的指针。
相比 iface,eface 就比较简单了。只维护了一个 _type 字段,表示空接口所承载的具体的实体类型。data 描述了具体的值。
从前面iface源码里可以看到:iface包含两个字段:tab 是接口表指针,指向类型信息;data 是数据指针,则指向具体的数据。它们分别被称为动态类型和动态值。
首先明确一下接口值包括动态类型和动态值。接口值的零值是指动态类型和动态值都为 nil。当仅且当这两部分的值都为 nil 的情况下,这个接口值就才会被认为 接口值 == nil。
让我们看一个例子:
package main
import "fmt"
type Coder interface {
code()
}
type Gopher struct {
name string
}
func (g Gopher) code() {
fmt.Printf("%s is coding\n", g.name)
}
func main() {
var c Coder
fmt.Println(c == nil) //true
fmt.Printf("c: %T, %v\n", c, c)
var g *Gopher
fmt.Println(g == nil) //true
c = g
fmt.Println(c == nil) //false
fmt.Printf("c: %T, %v\n", c, c)
}
结果如下:
一开始,c 的 动态类型和动态值都为 nil,g 也为 nil,当把 g 赋值给 c 后,c 的动态类型变成了 *main.Gopher,仅管 c 的动态值仍为 nil,但是当 c 和 nil 作比较的时候,结果就是 false 了。
我们知道,Go 语言中不允许隐式类型转换,也就是说 = 两边,不允许出现类型不相同的变量。
类型转换、类型断言本质都是把一个类型转换成另外一个类型。不同之处在于,类型断言是对接口变量进行的操作。
类型转换是将一个变量的类型转换为另一个类型。在 Go 中,类型转换使用如下语法:
//类型转换语法
destinationType(variable)
// 例如:将float64类型的变量转换为int类型
var myFloat float64 = 3.14
var myInt int
myInt = int(myFloat)
注意,当进行类型转换时,可能会丢失一些信息(例如,将浮点数转换为整数时,小数部分将被舍去)。
类型断言用于在接口类型和具体类型之间进行转换。类型断言的语法如下:
value, ok := interfaceVariable.(ConcreteType)
//如果断言成功,ok 的值将为 true,并且 value 将包含接口变量的具体类型值。如果断言失败,ok 的值将为 false,并且 value 将为具体类型的零值。
type Shape interface {
Area() float64
}
type Circle struct {
Radius float64
}
//你可以使用类型断言来检查一个 Shape 类型的变量是否包含一个 Circle 类型的值:
func main() {
var myShape Shape
myShape = Circle{Radius: 5}
if circle, ok := myShape.(Circle); ok {
fmt.Println("The shape is a circle with radius", circle.Radius)
} else {
fmt.Println("The shape is not a circle")
}
}
【有汇编分析,不错】http://legendtkl.com/2017/07/01/golang-interface-implement/
【interface 源码解读 很不错 包含反射】http://wudaijun.com/2018/01/go-interface-implement/
【类型转换和断言】https://www.cnblogs.com/zrtqsk/p/4157350.html
【断言】https://studygolang.com/articles/11419