深入学习Go-5 反射

反射是指程序在运行时可以访问、检测和修改自身状态和行为的一种能力。本质就是程序在运行期获取对象的类型和内存结构。

反射的基本类型与函数

Go语言的反射包里有两个基本类型和两个基本函数:

  • reflect.Type:接口类型,提供一系列处理类型相关的操作

  • reflect.Value:结构体类型,提供一系列处理值相关的操作

  • reflect.TypeOf:提取interface{}的类型信息,返回Type类型

  • reflect.ValueOf:提取类型的值,返回Value类型

反射三大定律

第一定律:将interface{}类型变量转换成反射对象

type User struct {
    Name string
    Age  int
}

func first() {
    user := User{"Justin", 20}
    t := reflect.TypeOf(user)
    v := reflect.ValueOf(user)
    
   fmt.Println("反射后的类型:", t)
   fmt.Println("反射后的值:", v)
}

执行结果:

图片

第二定律:可以将反射对象还原成interface{}类型变量

func second() {
    user := User{"Bill", 18}
    v := reflect.ValueOf(user)
    u := v.Interface().(User)
    
    fmt.Println("还原成User:", u)
}

执行结果:

图片

第三定律:如果想要修改一个反射对象的值,那么它持有的值必须是可修改的

func third() {
    i := 1
    /** 在Go语言中,函数传参是按值传递,i 的值不可修改
    v := reflect.ValueOf(i)
    v.SetInt(2)
    */
    // 将变量i的地址作为参数传递,获取i的指针
    v := reflect.ValueOf(&i)
    // 获取指向i的变量,然后修改成2
    v.Elem().SetInt(2)
    fmt.Println(i)
}

结构体反射

遍历结构体字段

func structs() {
    user := User{"Justin", 20}
    t := reflect.TypeOf(user)
    v := reflect.ValueOf(user)
    
    // 遍历结构体字段
    fmt.Println("通过反射遍历User的字段:")
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        value := v.Field(i).Interface()
        fmt.Printf("%s %v = %v\n", field.Name, field.Type, value)
    }
}

执行结果:

图片

修改结构体字段值

func structs() {
    // 修改结构体字段的值
    v = reflect.ValueOf(&user)
    fv := v.Elem().FieldByName("Age")
    fv.Set(reflect.ValueOf(18))
    fmt.Println("通过反射修改User的Age:")
    fmt.Println(user)
}

执行结果:

图片

调用结构体方法

type User struct {
    Name string
    Age  int
}

func (u User) GetName() string {
    return u.Name
}

func (u *User) SetName(name string) {
    u.Name = name
}

func structs() {
    user := User{"Justin", 18}
    v := reflect.ValueOf(user)

    // 调用无参数的方法
    m := v.MethodByName("GetName")
    args := make([]reflect.Value, 0)
    values := m.Call(args)
    fmt.Println("调用无参数的方法: GetName, 返回值: ", values)

    // 调用有参数的方法且方法是指针接收者
    v = reflect.ValueOf(&user)
    m = v.MethodByName("SetName")
    args = []reflect.Value{reflect.ValueOf("Bill")}
    m.Call(args)
    fmt.Println("调用有参数的方法: SetName, name: ", user.Name)
}

执行结果:

图片

函数反射

函数反射的调用与结构体方法的反射调用类似

func Add(i int, j *int) int {
    return i + *j
}

func funcs() {
    v := reflect.ValueOf(Add)
    j := 2
    args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(&j)}
    values := v.Call(args)
   fmt.Println(values[0])
}

执行结果:3

总结

反射最核心的基本类型和函数:reflect.Type、reflectValue和reflect.TypeOf、reflect.ValueOf;反射对象与interface{}类型变量可以互相转换,如果修改反射对象的值,那么这个变量本身是可修改的;结构体方法的反射调用与函数的反射调用类似。


 更多【分布式专辑】【架构实战专辑】系列文章,【招聘信息】请关注公众号

猜你喜欢

转载自blog.csdn.net/lonewolf79218/article/details/121744406