使用的一般步骤:

  • 定义一个接口
  • 定义一个以此接口作为第一个参数函数
  • 定义多个结构体
  • 多个结构体实现该接口
  • 使用接口:调用接口声明的函数,把结构体作为第一个参数传进去,或者使用接口类型直接调用方法。
  • 如果通过结构体直接调用方法,就没接口什么事了,也不涉及多态。

go 的鸭子类型归功于编译器的隐式类型转换。
调用接口规定的函数时,会隐式把传进去的结构体隐式转为接口类型。

不管方法的接受者是什么类型,该类型(不是接口类型)的值或指针都可以调用。
值类型调用者,指针类型接受者,使用值的引用来调用此方法。
指针类型调用者,值类型接受者,指针被解引用为值。

而对于接口类型,想调用方法,需要记住:
如果实现了接收者是值类型的方法,会隐含地也实现了接收者是指针类型的方法。

接受者定义为值类型,还是指针类型,由接受者类型本身来决定!

  • 内置原始类型,int、string等,值接受类型。

  • 内置引用类型,slice,map,interface,channel,值接受类型;声明它们时实质是创建了一个 header,复制它们实质复制的是 header,header 本身就为复制而设计的。

  • 类型不具备原始本质 ,不能被安全的复制,就应该设计为指针接受类型。如文件结构体 struct file。

go 类型

_type 结构体是 go 语言实现各种结构体的基础 ,也就是 go 的各种结构体是在 _type 结构基础上增加一些字段。

这是反射实现的基础。

  1. type _type struct {
  2. // 类型大小
  3. size uintptr
  4. ptrdata uintptr
  5. // 类型的 hash 值
  6. hash uint32
  7. // 类型的 flag,和反射相关
  8. tflag tflag
  9. // 内存对齐相关
  10. align uint8
  11. fieldalign uint8
  12. // 类型的编号,有bool, slice, struct 等等等等
  13. kind uint8
  14. alg *typeAlg
  15. // gc 相关
  16. gcdata *byte
  17. str nameOff
  18. ptrToThis typeOff
  19. }

接口类型定义:

  1. type iface struct {
  2. tab *itab
  3. data unsafe.Pointer
  4. }


接口包括两字段 tab 是接口表指针,指向动态类型,data 是数据指针,指向动态值
当且仅当这两者都为 nil 时,接口值才为 nil 。

类型断言,对接口类型进行转换。