# 10. interface
# 10.1 底层
底层是 runtime/runtime2.go
下的 iface
。
type iface struct {
tab *itab // interface 的标签信息
data unsafe.Pointer // 万能指针:指向真实数据
}
// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs.
type itab struct {
inter *interfacetype // 当前接口类型
_type *_type // 当前接口值所指向的真正类型
hash uint32
_ [4]byte
fun [1]uintptr // 记录当前值所指向的类型,实现了哪些方法;长度会在编译的时候变化,并非为1
// fun 字段是用来做【类型断言】的
}
# 10.2 结构体和其指针实现接口的问题
如果是用结构体类型去实现接口,Go 在编译的时候,会自动再为其对应的指针类型实现接口;
// 手动写 func (t Truck) Drive() { } // Go 底层会帮我们自动写这个 func (t *Truck) Drive() { }
如果只是用结构体指针类型去实现接口,Go 在编译的时候,就不会为结构体类型去实现接口;
// 手动写 func (t *Truck) Drive() { } /* Go 底层不会帮我们写这个 func (t Truck) Drive() { } */
# 10.3 空接口如何承载一切类型
空接口底层是 runtime/runtime2.go
下的 eface
类型:
type eface struct {
_type *_type // 当前接口值所指向的真正类型
data unsafe.Pointer // 万能指针:指向真实数据
}
# 10.4 nil & 空接口 & 空结构体
总结
- nil 是六种类型的零值,不包括基本类型和 struct;
- 空接口可以承载任意类型,只有当
_type
和data
都为空的时候,它才是 nil; - 空结构体的指针和值都不是 nil;
# 10.4.1 nil
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int
nil 只能是以下六种类型的零值:
- pointer
- channel
- func
- interface
- map
- slice
nil 不是 struct 的零值,不可能等于 struct{}。
nil 也不是基本类型的零值,不可能等于任意基本类型。
nil 是有类型的。
var a int
fmt.Println(a == nil) // 报错,nil 不支持基本类型
var ap *int
fmt.Println(ap == nil) // true
var b map[int]struct{}
fmt.Println(b == nil) // true
var s struct{}
fmt.Println(s == nil) // 报错,nil 不支持 struct
fmt.Println(ap == b) // 报错,虽然 ap 和 b 都是 nil,但是它们的类型是不一样的
# 10.4.2 空接口
var a interface{}
var b interface{}
var c *int
fmt.Println(a == nil) // true
fmt.Println(b == nil) // true
fmt.Println(c == nil) // true
fmt.Println(a == b) // true
fmt.Println(a == c) // false
a = c
fmt.Println(a == nil) // false
a == c
为false
我们可以理解,底层的数据类型是不一样的为什么
a = c
后,a
就不是nil
了呢?这是因为空接口的底层为我们上面分析的
eface
,当a=c
后,a
中的_type
字段就有值了,于是它就不是nil
了。type eface struct { _type *_type // a=c,后,_type 就是 *int 了 data unsafe.Pointer }
# 10.4.3 空结构体
- 啥也没有的结构体,它不可能等于 nil。
type A struct {
}