• go语言设计与实现-语言基础-阅读笔记


    函数调用

    • 传值:函数调用时会对参数进行拷贝,被调用方和调用方两者持有不相关的两份数据;
    • 传引用:函数调用时会传递参数的指针,被调用方和调用方两者持有相同的数据,任意一方做出的修改都会影响另一方。

    Go 语言选择了传值的方式,无论是传递基本类型、结构体还是指针,都会对传递的参数进行拷贝

    • 通过堆栈传递参数,入栈的顺序是从右到左;
    • 函数返回值通过堆栈传递并由调用者预先分配内存空间;
    • 调用函数时都是传值,接收方会对入参进行复制再计算;

    接口

    接口也是 Go 语言中的一种类型,它能够出现在变量的定义、函数的入参和返回值中并对它们进行约束,不过 Go 语言中有两种略微不同的接口,一种是带有一组方法的接口,另一种是不带任何方法的 interface{}

    Go 语言使用 iface 结构体表示第一种接口,使用 eface 结构体表示第二种空接口,两种接口虽然都使用 interface 声明,但是由于后者在 Go 语言中非常常见,所以在实现时使用了特殊的类型。

    type eface struct { // 16 bytes
        _type *_type
        data  unsafe.Pointer
    }

    由于 interface{} 类型不包含任何方法,所以它的结构也相对来说比较简单,只包含指向底层数据和类型的两个指针。从上述结构我们也能推断出 — Go 语言中的任意类型都可以转换成 interface{} 类型。

    另一个用于表示接口的结构体就是 iface,这个结构体中有指向原始数据的指针 data,不过更重要的是 itab 类型中的 tab 字段。

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

    _type 是 Go 语言类型的运行时表示。下面是运行时包中的结构体,结构体包含了很多元信息,例如:类型的大小、哈希、对齐以及种类等。

    type _type struct {
        size       uintptr
        ptrdata    uintptr
        hash       uint32
        tflag      tflag
        align      uint8
        fieldAlign uint8
        kind       uint8
        equal      func(unsafe.Pointer, unsafe.Pointer) bool
        gcdata     *byte
        str        nameOff
        ptrToThis  typeOff
    }
    • size 字段存储了类型占用的内存空间,为内存空间的分配提供信息;
    • hash 字段能够帮助我们快速确定类型是否相等;
    • equal 字段用于判断当前类型的多个对象是否相等,该字段是为了减少 Go 语言二进制包大小从 typeAlg 结构体中迁移过来

    itab 结构体是接口类型的核心组成部分,每一个 itab 都占 32 字节的空间,我们可以将其看成接口类型和具体类型的组合,它们分别用 inter 和 _type 两个字段表示

    type itab struct { // 32 bytes
        inter *interfacetype
        _type *_type
        hash  uint32
        _     [4]byte
        fun   [1]uintptr
    }

    除了 inter 和 _type 两个用于表示类型的字段之外,上述结构体中的另外两个字段也有自己的作用:

    • hash 是对 _type.hash 的拷贝,当我们想将 interface 类型转换成具体类型时,可以使用该字段快速判断目标类型和具体类型 _type 是否一致;
    • fun 是一个动态大小的数组,它是一个用于动态派发的虚函数表,存储了一组函数指针。虽然该变量被声明成大小固定的数组,但是在使用时会通过原始指针获取其中的数据,所以 fun 数组中保存的元素数量是不确定的

    反射

    三大法则
    从 interface{} 变量可以反射出反射对象
    从反射对象可以获取 interface{} 变量
    要修改反射对象,其值必须可设置

    由于 reflect.TypeOf、reflect.ValueOf 两个方法的入参都是 interface{} 类型,所以在方法执行的过程中发生了类型转换
    v.Interface().(type)

    从接口值到反射对象:
    从基本类型到接口类型的类型转换;
    从接口类型到反射对象的转换;
    从反射对象到接口值:
    反射对象转换成接口类型;
    通过显式类型转换变成原始类型;


    修改变量方式
    调用 reflect.ValueOf 函数获取变量指针;
    调用 reflect.Value.Elem 方法获取指针指向的变量;
    调用 reflect.Value.SetInt 方法更新变量的值
    emptyInterface
    type
    word
    reflect.TypeOf 函数的实现原理其实并不复杂,它只是将一个 interface{} 变量转换成了内部的 emptyInterface 表示,然后从中获取相应的类型信息。
    reflect.ValueOf 实现也非常简单,在该函数中我们先调用了 reflect.escapes 函数保证当前值逃逸到堆上,然后通过 reflect.unpackEface 方法从接口中获取 Value 结构体
    reflect.unpackEface 函数会将传入的接口转换成 emptyInterface 结构体,然后将具体类型和指针包装成 Value 结构体并返回

  • 相关阅读:
    文件处理--文件操作
    三元运算
    alex 推荐的书
    python字符串、列表和字典的说明
    运算符
    while else语句
    格式化输出
    数据类型-元组
    数据类型-集合
    字符串
  • 原文地址:https://www.cnblogs.com/lgh344902118/p/14459449.html
Copyright © 2020-2023  润新知