zoukankan      html  css  js  c++  java
  • Go:反射

    一、通过反射获取类型信息

    在 Go 程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func test1() {
        var a int
        t := reflect.TypeOf(a)
        fmt.Printf("name:%v kind:%v
    ", t.Name(), t.Kind()) // name:int kind:int
    }
    
    func test2() {
        type User struct {}
        user := User{}
        t := reflect.TypeOf(user)
        fmt.Printf("name:%v kind:%v
    ", t.Name(), t.Kind()) // name:User kind:struct
    }
    
    func main() {
        test1()
        test2()
    }
    View Code

    二、通过反射获取指针指向的元素类型

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        // 声明一个空结构体
        type User struct {}
        // 创建User的实例
        user := &User{}
        // 获取结构体实例的反射类型对象
        t := reflect.TypeOf(user)
        // 显示反射类型对象的名称和种类
        fmt.Printf("name:'%v' kind:'%v'
    ", t.Name(), t.Kind()) // name:'' kind:'ptr'
        // 获取指针类型的元素类型
        e := t.Elem()
        // 显示指针变量指向元素的类型名称和种类
        fmt.Printf("name:'%v' kind:'%v'
    ", e.Name(), e.Kind()) // name:'User' kind:'struct'
    }
    View Code

    三、通过反射获取结构体的成员类型

    任意值通过 reflect.TypeOf() 获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的 NumField() 和 Field() 方法获得结构体成员的详细信息。

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Name   string `json:"username"`
        Age    int
        Salary float64
    }
    
    func main() {
        user := User{"pd", 18, 9999.99}
        tf := reflect.TypeOf(user)
        // 遍历结构体所有成员
        for i := 0; i < tf.NumField(); i++ {
            // 获取每个成员的结构体字段类型
            fieldType := tf.Field(i)
            fmt.Printf("name:'%v' tag:'%v'
    ", fieldType.Name, fieldType.Tag)
            // name:'Name' tag:'json:"username"'
            // name:'Age' tag:''
            // name:'Salary' tag:''
        }
        // 通过字段名, 找到字段类型信息
        userType, ok := tf.FieldByName("Name")
        if ok {
            // 从tag中取出需要的tag
            fmt.Println(userType.Tag.Get("json")) // username
        }
    }
    View Code

    四、通过反射获取值信息

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        // 声明整型变量a并赋初值
        var a int
        a = 666
        // 获取变量a的反射值对象
        vf := reflect.ValueOf(a)
        // 将vf反射值对象以Interface{}类型取出, 通过类型断言转换为int类型
        r1 := vf.Interface().(int)
        // 将vf反射值对象以int64类型取出
        r2 := vf.Int()
        // 强制类型转换为int类型
        r3 := int(r2)
        fmt.Printf("r1值:%v r1类型:%T
    ", r1, r1) // r1值:666 r1类型:int
        fmt.Printf("r2值:%v r2类型:%T
    ", r2, r2) // r2值:666 r2类型:int64
        fmt.Printf("r3值:%v r3类型:%T
    ", r3, r3) // r3值:666 r3类型:int
    }
    View Code

    五、通过反射访问结构体成员的值

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Name   string
        Age    int
        Salary float64
    }
    
    func main() {
        user := User{"pd", 18, 9999.99}
        vf := reflect.ValueOf(user)
        // 获取字段数量
        fmt.Printf("NumField:%v
    ", vf.NumField()) // NumField:3
        // 获取索引为2的字段
        field := vf.Field(2)
        fmt.Println(field.Type()) // float64
        // 根据名字查找字段
        fbn := vf.FieldByName("Name")
        fmt.Println(fbn.Type()) // string
        // 根据索引查找字段
        fbi := vf.FieldByIndex([]int{1})
        fmt.Println(fbi.Type()) // int
    }
    View Code

    六、判断反射值的空和有效性

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        // *int的空指针
        var a *int
        fmt.Println(reflect.ValueOf(a).IsNil()) // true
    
        // nil值
        fmt.Println(reflect.ValueOf(nil).IsValid()) // false
    
        // 实例化一个结构体
        s := struct{}{}
        // 尝试从结构体中查找一个不存在的字段
        fmt.Println(reflect.ValueOf(s).FieldByName("").IsValid()) // false
    
        // 尝试从结构体中查找一个不存在的方法
        fmt.Println(reflect.ValueOf(s).MethodByName("").IsValid()) // false
    }
    View Code

    七、通过反射修改变量的值

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        // 声明整型变量a并赋初值
        var a int
        var b string
        a = 100
        b = "哈哈哈"
        // 获取变量a、b的反射值对象(a、b的地址)
        vfa := reflect.ValueOf(&a)
        vfb := reflect.ValueOf(&b)
        // 取出a、b地址的元素(值)
        vfae := vfa.Elem()
        vfbe := vfb.Elem()
        // 修改a、b的值
        vfae.SetInt(200)
        vfbe.SetString("嘻嘻嘻")
        // 打印a、b的值
        fmt.Println(a, b) // 200 嘻嘻嘻
    }
    View Code
    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Name string
        Age int
    }
    
    func main() {
        user := User{"pd", 18}
        vf := reflect.ValueOf(&user)
        // 取出User实例地址的元素
        vfe := vf.Elem()
        // 获取Name字段的值
        name := vfe.FieldByName("Name")
        // 修改此实例(对象)对应字段的值
        name.SetString("佩奇")
        fmt.Println(user) // {佩奇 18}
    }
    View Code

    八、通过类型信息创建实例

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        var a int
        // 取变量a的反射类型对象
        tf := reflect.TypeOf(a)
        // 根据反射类型对象创建这个类型的实例值,值以 reflect.Value 类型返回
        obj := reflect.New(tf)
        // 输出类型和种类
        fmt.Printf("type:%v kind:%v
    ", obj.Type(), obj.Kind()) // type:*int kind:ptr
    }
    View Code

    九、通过反射调用函数、方法

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    // add函数
    func add(a, b int) int {
        return a + b
    }
    
    func main() {
        // 将函数包装为反射值对象
        vf := reflect.ValueOf(add)
        // 构造函数参数, 传入两个整型值
        paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}
        // 反射调用函数
        retList := vf.Call(paramList)
        // 获取第一个返回值, 取整数值
        fmt.Println(retList[0].Int()) // 30
    }
    View Code
    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Name string
    }
    
    func (u *User) Hello(name string) {
        fmt.Printf("%s对%s打了一个招呼...
    ", u.Name, name) // pd对佩奇打了一个招呼...
    }
    
    func main() {
        user := User{"pd"}
        vf := reflect.ValueOf(&user)
        method := vf.MethodByName("Hello")
        // 方式1
        // args := []reflect.Value{reflect.ValueOf("佩奇")}
        // 方式2
        var args []reflect.Value
        args = append(args, reflect.ValueOf("佩奇"))
        // 调用方法
        method.Call(args)
    }
    View Code
  • 相关阅读:
    学习笔记——SQL SERVER2014内存数据库
    学习笔记——WCF
    线程
    文件内容操作类-RandomAccessFile
    文件操作类-file-创建文件夹
    同步方法解决同步问题
    同步代码块
    停止线程
    使用泛型来优化坐标类
    数据操作流-DataOutputStream
  • 原文地址:https://www.cnblogs.com/believepd/p/10976560.html
Copyright © 2011-2022 走看看