# 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 结构体和其指针实现接口的问题

image-20220813175004083
  • 如果是用结构体类型去实现接口,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;
  • 空接口可以承载任意类型,只有当 _typedata 都为空的时候,它才是 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 == cfalse 我们可以理解,底层的数据类型是不一样的

  • 为什么 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 {
  
}
上次更新: 8/14/2022, 9:54:10 AM