目录

一 反射的使用

1.1 反射操作简单数据类型

    var num int64 = 100

    // 设置值:指针传递
    ptrValue := reflect.ValueOf(&num)
    newValue := ptrValue.Elem()                         // Elem()用于获取原始值的反射对象
    fmt.Println("type:", newValue.Type())                // int64
    fmt.Println(" can set:", newValue.CanSet())        // true
    newValue.SetInt(200)

    // 获取值:值传递
    rValue := reflect.ValueOf(num)
    fmt.Println(rValue.Int())                    // 方式一:200
    fmt.Println(rValue.Interface().(int64))        // 方式二:200

1.2 反射进行类型推断

    type user struct {
        Name string
        Age int
    }

    u := &user{
        Name: "Ruyue",
        Age:  100,
    }

    fmt.Println(reflect.TypeOf(u))            // *main.user
    fmt.Println(reflect.TypeOf(*u))            // main.user
    fmt.Println(reflect.TypeOf(*u).Name())    // user
    fmt.Println(reflect.TypeOf(*u).Kind())    // struct

1.3 反射操作指针

    type user struct {
        Name string
        Age int
    }

    u := &user{
        Name: "Ruyue",
        Age:  100,
    }

    typeOfUser = reflect.TypeOf(u).Elem()
    fmt.Println("element name: ", typeOfUser.Name())        // user
    fmt.Println("element kind: ", typeOfUser.Kind())        // struct

1.4 反射操作结构体

反射可以获取结构体的详细信息:

    type user struct {
        Name string
        Age  int `json:"age" id:"100"` // 结构体标签
    }

    s := user{
        Name: "zs",
        Age:  1,
    }

    typeOfUser := reflect.TypeOf(s)

    // 字段用法
    for i := 0; i < typeOfUser.NumField(); i++ {        // NumField 当前结构体有多少个字段
        fieldType := typeOfUser.Field(i)                // 获取每个字段
        fmt.Println(fieldType.Name, fieldType.Tag)
    }
    if userAge, ok := typeOfUser.FieldByName("Age"); ok {
        fmt.Println(userAge)                        // {Age  int json:"age" id:"100" 16 [1] false}
    }

    // 方法用法
    for i := 0; i < typeOfUser.NumMethod(); i++ {
        fieldType := typeOfUser.Method(i)                // 获取每个字段
        fmt.Println(fieldType.Name)
    }

二 反射调用函数与方法

2.1 使用反射调用函数

如果反射值对象(reflect.Value)中值的类型为函数时,可以通过 reflect.Value调用该 函数。使用反射调用函数时,需要将参数使用反射值对象的切片 口reflect.Value 构造后传入 Call()方法中 , 调用完成时,函数的返回值通过 []reflect.Value 返回 。

func add(name string, age int) {
    fmt.Printf("name is %s, age is %d \n", name, age)
}

func main() {
    funcValue := reflect.ValueOf(add)
    params := []reflect.Value{reflect.ValueOf("lisi"), reflect.ValueOf(20)}

    reList := funcValue.Call(params)
    fmt.Println(reList)            // 函数返回值
}

2.2 反射调用方法

方法的调用是需要接收者的:

package main

import (
    "fmt"
    "reflect"
)

type user struct {
    Name string
    Age int
}
func (u *user) ShowName() {
    fmt.Println(u.Name)
}

func (u *user) AddAge(addNum int) {
    fmt.Println("age add result:", u.Age + addNum)
}

func main() {

    u := &user{"lisi", 20}
    v := reflect.ValueOf(u)

    // 调用无参方法
    methodV := v.MethodByName("ShowName")
    methodV.Call(nil)        // 或者传递一个空切片也可

    // 调用有参方法
    methodV2 := v.MethodByName("AddAge")
    args := []reflect.Value{reflect.ValueOf(30)}    //
    methodV2.Call(args)
}