网站营销特点,怎么去推广一个网站,wordpress缩 图,大连公共资源交易平台官网我们知道GO可以通过定义接口#xff0c;将具体的实现和调用完全分离#xff0c;其本质就是引入一个中间层对不同的模块进行解耦#xff0c;上层的模块就不需要依赖某一个具体的实现#xff0c;而是只需要依赖一个定义好的接口。那么#xff0c;在理解了如何使用Go的interf… 我们知道GO可以通过定义接口将具体的实现和调用完全分离其本质就是引入一个中间层对不同的模块进行解耦上层的模块就不需要依赖某一个具体的实现而是只需要依赖一个定义好的接口。那么在理解了如何使用Go的interface后了解其内部实现有助于我们更好的使用这套机制。作为上篇的补充这次把对interface的内部实现做了个整理。 interface底层上是分别由两个struct实现iface和eface。eface表示empty interface不包含任何方法iface 表示 non-empty interface即包含方法的接口。从概念上来讲iface和eface均由两部分组成type和valuetype表示interface的类型描述主要提供concrete type相关的信息value指向interface绑定的具体数据。 具体类型实例传递给接口称为接口的实例化这里有个地方值得注意Interface变量默认值为nil需要初始化后才有意义。 eface 先从较简单的eface看起空接口eface结构比较简单由两个属性构成一个是类型信息_type一个是数据信息。其数据结构声明如下 type eface struct {_type *_typedata unsafe.Pointer
}其中_type是GO语言中所有类型的公共描述Go语言几乎所有的数据结构都可以抽象成 _type是所有类型的公共描述type负责决定data应该如何解释和操作type的结构代码如下: type _type struct {size uintptr ptrdata uintptr // size of memory prefix holding all pointershash uint32 // 类型哈希tflag tflagalign uint8 // _type作为整体变量存放时的对齐字节数fieldalign uint8kind uint8alg *typeAlg// gcdata stores the GC type data for the garbage collector.// If the KindGCProg bit is set in kind, gcdata is a GC program.// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.gcdata *bytestr nameOffptrToThis typeOff // type for pointer to this type, may be zero
}data表示指向具体的实例数据由于Go的参数传递规则为值传递如果希望可以通过interface对实例数据修改则需要传入指针此时data指向的是指针的副本但指针指向的实例地址不变仍然可以对实例数据产生修改。 Eface的结构 iface iface 表示 non-empty interface 的数据结构非空接口初始化的过程就是初始化一个iface类型的结构其中data的作用同eface的相同这里不再多加描述。 type iface struct {tab *itabdata unsafe.Pointer
}iface结构中最重要的是itab结构结构如下每一个 itab 都占 32 字节的空间。itab可以理解为pairinterface type, concrete type 。itab里面包含了interface的一些关键信息比如method的具体实现。 // 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.dumptypestructs.
type itab struct {inter *interfacetype // 接口自身的元信息_type *_type // 具体类型的元信息link *itabbad int32hash int32 // _type里也有一个同样的hash此处多放一个是为了方便运行接口断言fun [1]uintptr // 函数指针指向具体类型所实现的方法
}
type interfacetype struct {typ _typepkgpath namemhdr []imethod
}
type imethod struct { //这里的 method 只是一种函数声明的抽象比如 func Print() errorname nameOffityp typeOff
}其中值得注意的字段个人理解如下 interface type包含了一些关于interface本身的信息比如package path包含的method。上面提到的iface和eface是数据类型转换成interface之后的实体struct结构而这里的interfacetype是定义interface的一种抽象表示。type表示具体化的类型与eface的 type类型相同。hash字段其实是对_type.hash的拷贝它会在interface的实例化时用于快速判断目标类型和接口中的类型是否一致。另Go的interface的Duck-typing机制也是依赖这个字段来实现。fun字段其实是一个动态大小的数组虽然声明时是固定大小为1但在使用时会直接通过fun指针获取其中的数据并且不会检查数组的边界所以该数组中保存的元素数量是不确定的。 补充fun个人理解是类似于C中的虚函数指针的存在当通过接口调用函数时实际操作就是s.itab-func()。但不同与C的虚表之处是GO是在运行时生成虚表保障了唯一性避免了C中可能存在的同一个接口在不同层次被多次继承实现的等一系列问题但这里会产生额外的时间消耗。 Iface结构如下 Iface结构 interface设计的优缺点 优点非侵入式设计写起来更自由无需显式实现只要实现了与 interface 所包含的所有函数签名相同的方法即可。 缺点duck-typing风格并不关注接口的规则和含义也没法检查不确定某个struct具体实现了哪些interface。只能通过goru工具查看。 上篇 罗晓GO如何支持泛型zhuanlan.zhihu.com 参考 https://research.swtch.com/interfaces https://golang.org/doc/asm