首页 > 其他分享 >go 接口

go 接口

时间:2023-01-18 21:00:37浏览次数:38  
标签:itab struct 非空 接口 类型 go type

接口的值

接口的值简单来说,是由两部分组成的,就是类型和数据。

那么判断两个接口是相等,就是看他们的这两部分是否相等;另外类型和数据都为nil才代表接口是nil,这里就解释了上面的问题。由于golang的err实现是一个接口,所以很容易在err的处理过程中写错。

接口的数据结构

go的接口有两种结构,一种是有方法定义的接口,一种是空接口,分别对应两种实现。

空接口的实现

空接口通过eface结构定义实现,位于/src/runtime/runtime2.go

type eface struct {
    _type *_type
    data unsafe.Pointer
}

eface包含了2个元素,一个是_type,指向对象的类型元数据,一个 data,数据指针。

 

 

type _type struct {
    size       uintptr // 类型占用内存大小
    ptrdata    uintptr // 包含所有指针的内存前缀大小
    hash       uint32  // 类型 hash
    tflag      tflag   // 标记位,主要用于反射
    align      uint8   // 对齐字节信息
    fieldAlign uint8   // 当前结构字段的对齐字节数
    kind       uint8   // 基础类型枚举值
    equal func(unsafe.Pointer, unsafe.Pointer) bool // 比较两个形参对应对象的类型是否相等
    gcdata    *byte    // GC 类型的数据
    str       nameOff  // 类型名称字符串在二进制文件段中的偏移量
    ptrToThis typeOff  // 类型元信息指针在二进制文件段中的偏移量
}

1,kind,这个字段描述的是如何解析基础类型。在 Go 语言中,基础类型是一个枚举常量,有 26 个基础类型,如下。枚举值通过 kindMask 取出特殊标记位。

 

const (
    kindBool = 1 + iota
    kindInt
    kindInt8
    kindInt16
    kindInt32
    kindInt64
    kindUint
    kindUint8
    kindUint16
    kindUint32
    kindUint64
    kindUintptr
    kindFloat32
    kindFloat64
    kindComplex64
    kindComplex128
    kindArray
    kindChan
    kindFunc
    kindInterface
    kindMap
    kindPtr
    kindSlice
    kindString
    kindStruct
    kindUnsafePointer

    kindDirectIface = 1 << 5
    kindGCProg      = 1 << 6
    kindMask        = (1 << 5) - 1
)

以下面两个例子为例:

指针的类型元数据在_type结构体后面,记录着一个*_type,指向其存储元素的类型元数据。
如一个空接口被赋值了指向int的一个指针,那么ptrtype中的elem就指向int的元数据结构体。
type ptrtype struct { type __type elem *_type }

 

 非空接口

空接口由于不包含方法,所以结构简单。非空接口的底层实现:

type iface struct {
    tab *itab
    data unsafe.Pointer
}

tab中存放的是类型,方法等信息,data指针指向的是iface绑定对象的原始数据。

type itab struct {
        //inter 和 _type 确定唯一的 _type类型
    inter *interfacetype //接口自身定义的类型信息,用于定位到具体interface类型
    _type *_type  // 接口实际指向值的类型信息-实际对象类型,用于定义具体interface类型
    hash  uint32 //_type.hash的拷贝,用于快速查询和判断目标类型和接口中类型是一致
    _     [4]byte
    fun   [1]uintptr //动态数组,接口方法实现列表(方法集),即函数地址列表,按字典序排序
                         //如果数组中的内容为空表示 _type 没有实现 inter 接口
}

 

itab.inter是interface的类型元数据,它记录了这个接口类型的描述信息,接口要求的方法列表就记录在interfacetype.mhdr这里。

type interfacetype struct {
    typ _type
    pkgpath name
    mhdr []imethod
}

tab._type就是接口的动态类型,也就是被赋给接口类型的那个变量的类型元数据。itab中的_type和iface中的data能简要描述一个变量。_type是这个变量对应的类型,data是这个变量的值。

 

 itab.hash是从itab.type中拷贝来的,是类型的哈希值,用于快速判断类型是否相等时使用。

itab.fun记录的是动态类型实现的那些接口要求的方法的地址,是从方法元数据中拷贝来的,为的是快速定位到方法。

如果itab._type对应的类型没有实现这个接口,则itab.fun[0]=0,这在类型断言时会用到。当fun[0]为0时,说明_type并没有实现该接口,当实现接口时,fun存放了第一个接口方法的地址。

 

 

 

itab缓存

对于itab来说,既然一个非空接口类型和一个动态类型就可以确定一个itab的内容,那么这个itab结构体自然是可以被接口类型和动态类型均相同的接口变量复用的。这就是itabTable.

const itabInitSize = 512

type itabTableType struct {
    size uintptr
    count uintptr
    entries [itabInitSize]*itab
}
    

可以看出这个全局的itabTable是以数组的形式存储的,size记录数组的大小,总是2的次幂

count记录数组中已使用了多少。

entries 是一个 *itab数组,初始大小为512.

需要一个itab时,会首先去itabTable里查找,计算哈希值时会用到接口类型(itab.inter)和动态类型(itab._type)的类型哈希值。

func itabHashFunc(inter *interfacetype, typ *_type) uintptr {
    return uintptr(inter.typ.hash ^ typ.hash)
}

如果能查询到对应的itab指针,就直接拿来使用。若没有就要再创建,然后添加到itabTable中。

 

 

 

 类型断言

一,空接口.(具体类型)

 

 每个具体类型的元数据都是全局唯一的。

 二,非空接口.(具体类型)

 

 三,空接口.(非空接口)

 

 

 

 先去itab缓存中查找,查到后检查是否itab.fun[0] == 0。若缓存中不存在,就去检查_type对应的类型元数据的方法是否在非空接口中都有对应。

四,非空接口.(非空接口)

 

 

 

 

标签:itab,struct,非空,接口,类型,go,type
From: https://www.cnblogs.com/dadishi/p/17060558.html

相关文章

  • Django一个“高质量”小白的学习之路(给自己看)
     第一天day1:人类的思维倾向于直白、视觉和线性,还有好奇心,这是祖先遗传下来的思维习惯。如果论结果,显然我是一个计算机学习的失败者。因为我作为一个已经刚到不惑之年......
  • hugo 使用
    同步使用rsync来进行同步,linux系统中rsync速度快于rclone。rclone只是多提供了云服务商。服务端安装rsyncsudoyuminstall-yrsync服务端配置vim/etc/rs......
  • MeterSphere 接口自动化插件基础开发教程
    背景介绍从MeterSpherev1.13版本开始,接口自动化支持了通过添加插件的方式进行扩展。针对JMeter已有的功能或插件,只需要进行很少量的开发工作,就可以将其包装成一个Mete......
  • 90%开发都会忽略的性能调优点:针对返回大数据量的接口,10分钟内找到提升带宽瓶颈的突破
    01问题现象前几天小编居家远程办公,在测试环境访问某返回3.4M数据的接口,响应速度远不如预期。一开始怀疑是用远程用vpn连接访问导致的。但回到公司之后,我再次通过内网多次访......
  • MeterSphere 接口自动化 CSV 整合 JSON 文件
    在 ToB系统的业务场景中,经常有厂家需要将原始JSON数据,用于请求体传参,或者响应体对比等业务场景。对应Metersphere中接口自动化,CSV数据驱动数据包含JSON结构内容,用......
  • MeterSphere 之 IDEA 接口同步插件
    1安装插件1.1、插件安装有两种方式在线安装:直接在idea->Settings->plugins->Marketplace搜索MeterSphere在线安装离线安装:下载安装包,idea->Settings->plugins......
  • GO语言实现一个简单的命令行词典
    一个命令行词典,使用浏览器中的开发者工具进行抓包。拿到接口后再在IDE中进行实现。抓包打开检查后找到dict查看状态代码是否为POST,复制dict选择复制为cURL(bash)拿到接......
  • 备份:TVBox配置接口
    TVBox配置接口唐三:https://hutool.ml/tang(复制粘贴进壳食用)FongMi:https://raw.iqiq.io/FongMi/CatVodSpider/main/json/config.json巧技:http://pandown.pro/tvbox/......
  • 13.进一步认识Cargo及crates.io
    一、使用发布配置来定制构建Rust中的发布配置是一系列预定义好的配置方案,它们的配置选项各有不同,都允许程序员对细节进行定制修改。Cargo最常用的配置有两种:执行cargob......
  • hugo 部署到服务器
    创建用户,并有sudo权限useraddxyzpasswdxyzusermod-aGwheelxyzsudo-l检查端口sudonetstat-tulpn|grep:80sudonetstat-tulpn|grep:443安装ngin......