go语言反射

时间:2022-07-24
本文章向大家介绍go语言反射,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

反射的特点

  • 反射功能具有强大的功能
  • 反射是用程序检查其所拥有的结构,尤其是类型的一种能力
  • 是元编程的一种形式
  • 我们可以在【运行时】通过反射来分析一个结构体
  • 检查其类型和变量(类型和取值)和方法
  • 动态的修改变量和调用方法
  • 这对于没有源代码的包尤其有用
  • 这是一个强大的工具,除非真的有必要,否则应当避免使用或者小心使用

反射API

TypeOf

oType := reflect.TypeOf(obj)
t.Name()
kind := oType.Kind()
    kind:struct 系统类型的枚举
    type: 具体的类
t.NumField()
t.NumMethod()
structField := oType.Field(i)
    structField.Name
    structField.Type

method := oType.Method(i)
    methodType := methodType
        argNum := method.Type.NumIn()  参数个数
        artType := method.Type.In(0)  第1个参数类型
t.FieldByIndex([]int{0, 1})
    找出第0个父结构体中的第1个属性

ValueOf

oValue := reflect.ValueOf(obj) field := oValue.Field(i) -> fieldValue :=value.Field(i).Interface{}(获取第i个属性的值的“正射”形式)

fieldValue := value.FieldByIndex([]int{0, 0}).Interface()  找出第0个父结构体中的第0个属性值


oPtrValue.Elem() 获取地址value中的值value

oPtrValue.Elem().CanSet()  检查当前地址value内的值是否可以改变(可改变条件:可寻址+不来字非导出字段)

 oPtrValue.Elem().SetInt(999)

 value.SetString("jack")

 nameValue := value.FieldByName("Name")


 isVaild := value.IsVaild()  nil(0值)非法  非常罕见

 kind := value.Kind()和type.Kind()一样
 mathod := oValue.Method(i)   通过方法的值可以调取方法
 methodValue.Call([]reflect.Value{val1,val2})

代码实例(简单类型的反射操作)

package main
import (
    "fmt"
    "reflect"
)
//简单类型的反射
func reflectTest01(b interface{}) {
    //通过反射来获取传入变量的   type,kind。值
    //1.先获取到reflect.Type
    rType := reflect.TypeOf(b)
    fmt.Println("rType = ", rType)
    //2.获取到reflect.Value
    rVal := reflect.ValueOf(b)
    n2 := 2 + rVal.Int()

    fmt.Println("n2 = ", n2)
    fmt.Printf("rVal = %v, rVal type=%Tn", rVal, rVal)
    //下面我们将rVal转换成interface
    iv := rVal.Interface()
    //将interface通过断言转换成需要的类型
    num2 := iv.(int)
    fmt.Println("num2 = ", num2)
}

//复杂类型的反射
func reflectTest02(b interface{}) {
    //通过反射获取到传入变量的type  kind值
    rType := reflect.TypeOf(b)
    fmt.Println("rType =", rType)

    //获取到reflectValue
    rVal := reflect.ValueOf(b)

    //获取变量对应的kind
    typeKind := rType.Kind()
    valKind := rVal.Kind()
    fmt.Printf("typeKind = %v, valKind = %vn", typeKind, valKind)

    //将rVal转换为interface{}
    iv := rVal.Interface()
    fmt.Printf("iv = %v is type =%Tn", iv, iv)
    //把interface{}通过断言转换成需要的类型
    stu, ok := iv.(Student)
    if ok {
        fmt.Println("stu.Name = ", stu.Name)
    }
}
func changeValue(b interface{}) {
    rVal := reflect.ValueOf(b)
    fmt.Printf("rVal kind =%vn", rVal.Kind())
    rVal.Elem().SetInt(1)
}

type Student struct {
    Name string
    Age  int
}

func main() {
    var b int = 10
    reflectTest01(b)
    fmt.Println("-------------")

    stu := Student{
        Name: "tom",
        Age:  12,
    }
    reflectTest02(stu)
    fmt.Println("-------------")
    var c int = 100
    changeValue(&c)
    fmt.Println(c)
}

反射操作相关代码(结构体)

package main
import (
    "fmt"
    "reflect"
)
type Monster struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Score float32
    Sex   string
}

func (s Monster) Print() {
    fmt.Println("-----start-------")
    fmt.Println(s)
    fmt.Println("-----end-------")
}
func (s Monster) GetSum(n1, n2 int) int {
    return n1 + n2
}
func (s Monster) Set(name string, age int, score float32, sex string) {
    s.Name = name
    s.Age = age
    s.Score = score
    s.Sex = sex
}

func TestStruct(a interface{}) {
    rType := reflect.TypeOf(a)
    rVal := reflect.ValueOf(a)
    kd := rVal.Kind()
    if kd != reflect.Struct {
        fmt.Println("expect struct")
        return
    }
    num := rVal.NumField()
    fmt.Println("struct fields:", num)
    //变量结构体的所有字段
    for i := 0; i < num; i++ {
        fmt.Printf("field %d:值为:%vn", i, rVal.Field(i))
        tagVal := rType.Field(i).Tag.Get("json")
        if tagVal != "" {
            fmt.Printf("field %d: tag为=%vn", i, tagVal)
        }
    }

    //结构体的方法操作
    numOfMethod := rVal.NumMethod()
    fmt.Printf("struct has %d methodsn", numOfMethod)

    //var params []reflect.Value
    rVal.Method(1).Call(nil)

    //调用结构体的第1个方法Method(0)
    var params []reflect.Value
    params = append(params, reflect.ValueOf(10))
    params = append(params, reflect.ValueOf(40))
    res := rVal.Method(0).Call(params)
    fmt.Println("res = ", res[0].Int())
    //反射修改字段

}
func main() {
    var a Monster = Monster{
        Name:  "tom",
        Age:   100,
        Score: 30.1,
        Sex:   "男",
    }
    TestStruct(a)
}