[GO language foundation] GO reflection structure type to read data and its mechanism (12)

Article Directory

reflection

  • basic introduction
  1. Reflection can dynamically obtain various information about variables at runtime, such as variable type (type), category (kind)
  2. If it is a structure variable, you can also get the information of the structure itself (including the fields and methods of the structure)
  3. Through reflection, the value of the variable can be modified and the associated method can be called.
  4. To use reflection, import ("reflect") is required
  • Application scenarios
  1. I don't know which function the interface calls, and determine the specific interface called at runtime based on the incoming parameters. This needs to reflect on the function or method.
  2. When serializing the structure, if the structure has a specified Tag, reflection will also be used to generate the corresponding string.
  • Common functions and concepts
  1. reflect.TypeOf(variable name), get the type of the variable, return reflect.Type type
    //使用 reflect.TypeOf() 函数可以获得任意值的类型对象,通过类型对象可以访问任意值的类型信息。
	rTyp := reflect.TypeOf(b) 
	fmt.Println("rType=", rTyp)
  1. reflect.ValueOf(variable name), get the value of the variable and return reflect.

    Value type reflect.Value is-a structure type. Through reflect.Value, you can get a lot of information about the variable.

    //使用 reflect.TypeOf() 函数可以获得任意值的类型对象,通过类型对象可以访问任意值的类型信息。
	rTyp := reflect.TypeOf(b) 
	fmt.Println("rType=", rTyp)
  1. The variables interface() and reflect.Value can be converted to each other.
    var num int = 100
    rVal := reflect.ValueOf(b)
    //下面我们将 rVal 转成 interface{}
	iV := rVal.Interface()
	//将 interface{} 通过断言转成需要的类型
	num2 := iV.(int)
	fmt.Println("num2=", num2)
  1. reflect.TypeOf.Elem() Get the element type of the pointer type
type Student struct {
	Name string `json:"username"`
	Age int
}
func main() {
    stu := Student{
		Name : "tom",
		Age : 20,
	}
    rTyp := reflect.TypeOf(stu)

    // 获取指针类型的元素类型
    e := rTyp.Elem()
    // 显示指针变量指向元素的类型名称和种类
    fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct'
}
  1. After the reflection object information of any value is obtained through reflect.TypeOf(), if its type is a structure, the detailed information of the structure member can be obtained through the NumField() and Field() methods of the reflection value object (reflect.Type).
    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'\n", 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
        }
    }
  1. Obtain value information through reflection
    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\n", r1, r1) // r1值:666 r1类型:int
        fmt.Printf("r2值:%v r2类型:%T\n", r2, r2) // r2值:666 r2类型:int64
        fmt.Printf("r3值:%v r3类型:%T\n", r3, r3) // r3值:666 r3类型:int
    }
  1. Access the values ​​of structure members through reflection
    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\n", 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
    }
  1. Judge the null and validity of the reflection value
    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
    }
  1. Modify the variable by reflection. Note that when using the SetXxx method to set it needs to be done through the corresponding pointer type, so that the value of the passed variable can be changed, and the reflect.Value.Elem() method needs to be used.
    var num int = 10
    //2. 获取到 reflect.Value
	rVal := reflect.ValueOf(num)
	//3. Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
	rVal.Elem().SetInt(20)

    fmt.Println("num=", num) // 20
  1. Create an instance with type information
    func main() {
        var a int
        // 取变量a的反射类型对象
        tf := reflect.TypeOf(a)
        // 根据反射类型对象创建这个类型的实例值,值以 reflect.Value 类型返回
        obj := reflect.New(tf)
        // 输出类型和种类
        fmt.Printf("type:%v kind:%v\n", obj.Type(), obj.Kind()) // type:*int kind:ptr
    }
  1. Calling functions and methods through reflection
// 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
}
  • Precautions
  1. reflect.Value.Kind, get the category of the variable, and return a constant

  2. The difference between Type and Kind

    Type is the type, Kind is the category, Type and Kind may be the same or different.

    rTyp := reflect.TypeOf(b)
	rVal := reflect.ValueOf(b)
    //(1) rVal.Kind() ==> 
	kind1 := rVal.Kind()
	//(2) rTyp.Kind() ==>
	kind2 := rTyp.Kind()
  1. Through reflection, variables can be converted between interface() and Reflect.Value.
  2. Use reflection to get the value of the traffic (and return the corresponding type), requiring the data type to match
    var num int = 100
	rTyp := reflect.TypeOf(num)
	rVal := reflect.ValueOf(num)
	
	n2 := 2 + rVal.Int()
	//n3 := rVal.Float() //error panic
  1. Modify the variable by reflection. Note that when using the SetXxx method to set it needs to be done through the corresponding pointer type, so that the value of the passed variable can be changed, and the reflect.Value.Elem() method needs to be used.
    var num int = 10
    //2. 获取到 reflect.Value
	rVal := reflect.ValueOf(num)
	//3. Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
	rVal.Elem().SetInt(20)

    fmt.Println("num=", num) // 20
  1. reflect.Value.Elem() is used to get the pointer to the variable
    type User struct {
        Name   string
        Age    int
        Salary float64
    }
    func main() {
        // 声明一个空结构体
        type User struct {}
        // 创建User的实例
        user := &User{}
        // 获取结构体实例的反射类型对象
        t := reflect.TypeOf(user)
        // 显示反射类型对象的名称和种类
        fmt.Printf("name:'%v' kind:'%v'\n", t.Name(), t.Kind()) // name:'' kind:'ptr'
        // 获取指针类型的元素类型
        e := t.Elem()
        // 显示指针变量指向元素的类型名称和种类
        fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct'
    }

Guess you like

Origin blog.csdn.net/weixin_54707168/article/details/114006031