• 技术文章 >后端开发 >Golang

    go语言有反射吗

    青灯夜游青灯夜游2022-11-25 16:56:14原创135

    go语言有反射。Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。Go语言中的反射是由reflect包提供支持的,它定义了两个重要的类型Type和Value任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成。

    php入门到就业线上直播课:进入学习

    本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

    Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。

    go语言中的反射

    反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息。

    支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。

    C/C++语言没有支持反射功能,只能通过 typeid 提供非常弱化的程序运行时类型信息;Java、C# 等语言都支持完整的反射功能;Lua、JavaScript 类动态语言,由于其本身的语法特性就可以让代码在运行期访问程序自身的值和类型信息,因此不需要反射系统。

    Go语言程序的反射系统无法获取到一个可执行文件空间中或者是一个包中的所有类型信息,需要配合使用标准库中对应的词法、语法解析器和抽象语法树(AST)对源码进行扫描后获得这些信息。

    Go语言提供了 reflect 包来访问程序的反射信息。

    reflect 包

    Go语言中的反射是由 reflect 包提供支持的,它定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成,并且 reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 两个函数来获取任意对象的 Value 和 Type。

    反射的类型对象(reflect.Type)

    在Go语言程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息,下面通过示例来理解获取类型对象的过程:

    package main
    import (
        "fmt"
        "reflect"
    )
    func main() {
        var a int
        typeOfA := reflect.TypeOf(a)
        fmt.Println(typeOfA.Name(), typeOfA.Kind())
    }

    运行结果如下:

    1.png

    代码说明如下:

    反射的类型(Type)与种类(Kind)

    在使用反射时,需要首先理解类型(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个大品种的类型时,就会用到种类(Kind)。例如需要统一判断类型中的指针时,使用种类(Kind)信息就较为方便。

    1) 反射种类(Kind)的定义

    Go语言程序中的类型(Type)指的是系统原生数据类型,如 int、string、bool、float32 等类型,以及使用 type 关键字定义的类型,这些类型的名称就是其类型本身的名称。例如使用 type A struct{} 定义结构体时,A 就是 struct{} 的类型。

    种类(Kind)指的是对象归属的品种,在 reflect 包中有如下定义:

    type Kind uint
    const (
        Invalid Kind = iota  // 非法类型
        Bool                 // 布尔型
        Int                  // 有符号整型
        Int8                 // 有符号8位整型
        Int16                // 有符号16位整型
        Int32                // 有符号32位整型
        Int64                // 有符号64位整型
        Uint                 // 无符号整型
        Uint8                // 无符号8位整型
        Uint16               // 无符号16位整型
        Uint32               // 无符号32位整型
        Uint64               // 无符号64位整型
        Uintptr              // 指针
        Float32              // 单精度浮点数
        Float64              // 双精度浮点数
        Complex64            // 64位复数类型
        Complex128           // 128位复数类型
        Array                // 数组
        Chan                 // 通道
        Func                 // 函数
        Interface            // 接口
        Map                  // 映射
        Ptr                  // 指针
        Slice                // 切片
        String               // 字符串
        Struct               // 结构体
        UnsafePointer        // 底层指针
    )

    Map、Slice、Chan 属于引用类型,使用起来类似于指针,但是在种类常量定义中仍然属于独立的种类,不属于 Ptr。type A struct{} 定义的结构体属于 Struct 种类,*A 属于 Ptr。

    2) 从类型对象中获取类型名称和种类

    Go语言中的类型名称对应的反射获取方法是 reflect.Type 中的 Name() 方法,返回表示类型名称的字符串;类型归属的种类(Kind)使用的是 reflect.Type 中的 Kind() 方法,返回 reflect.Kind 类型的常量。

    下面的代码中会对常量和结构体进行类型信息获取。

    package main
    import (
        "fmt"
        "reflect"
    )
    // 定义一个Enum类型
    type Enum int
    const (
        Zero Enum = 0
    )
    func main() {
        // 声明一个空结构体
        type cat struct {
        }
        // 获取结构体实例的反射类型对象
        typeOfCat := reflect.TypeOf(cat{})
        // 显示反射类型对象的名称和种类
        fmt.Println(typeOfCat.Name(), typeOfCat.Kind())
        // 获取Zero常量的反射类型对象
        typeOfA := reflect.TypeOf(Zero)
        // 显示反射类型对象的名称和种类
        fmt.Println(typeOfA.Name(), typeOfA.Kind())
    }

    运行结果如下:

    2.png

    代码说明如下:

    指针与指针指向的元素

    Go语言程序中对指针获取反射对象时,可以通过 reflect.Elem() 方法获取这个指针指向的元素类型,这个获取过程被称为取元素,等效于对指针类型变量做了一个*操作,代码如下:

    package main
    import (
        "fmt"
        "reflect"
    )
    func main() {
        // 声明一个空结构体
        type cat struct {
        }
        // 创建cat的实例
        ins := &cat{}
        // 获取结构体实例的反射类型对象
        typeOfCat := reflect.TypeOf(ins)
        // 显示反射类型对象的名称和种类
        fmt.Printf("name:'%v' kind:'%v'\n", typeOfCat.Name(), typeOfCat.Kind())
        // 取类型的元素
        typeOfCat = typeOfCat.Elem()
        // 显示反射类型对象的名称和种类
        fmt.Printf("element name: '%v', element kind: '%v'\n", typeOfCat.Name(), typeOfCat.Kind())
    }

    运行结果如下:

    3.png

    代码说明如下:

    【相关推荐:Go视频教程

    以上就是go语言有反射吗的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:Go Golang go语言
    上一篇:golang有哪些优势 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 一文浅析Golang中的闭包• 什么是golang• golang能做什么• golang怎么进行数据类型转换• go就是golang吗
    1/1

    PHP中文网