Go语言之reflection

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言之reflection相关的知识,希望对你有一定的参考价值。

reflection 反射
  • 反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地
  • 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
  • 反射会将匿名字段作为独立字段(匿名字段本质)
  • 想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface
  • 通过反射可以"动态"调用方法

举例

1、通过反射来获取属性信息,方法信息

//反射  练习
//获取字段的类型信息,方法信息, 属性信息
package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Id int
    Name string
    Age int
}

func (user User) Hello(){
    fmt.Println("hello world")
}

func main() {
    user := User{Id:2, Name:"xiaoqiang",Age:30}
    info(user)
}

//定义一个方法
//此方法接收的是一个空接口
//这样的话,其实是任何类型都可以接收了
func info(o interface{}) {
    //获取o的类型
    t := reflect.TypeOf(o)

    fmt.Println("Type:\t", t.Name())

    //取出类型后,需要对类型进行校验,
    //查看是否是规定的类型
    if k :=t.Kind(); k != reflect.Struct {
        //如果不是规定的Struct类型的话,就需要进行
        //异常处理
        fmt.Println("输入参数的类型不匹配!")
        return
    }

    //获取o的属性
    v := reflect.ValueOf(o)
    fmt.Println("Fields:\n")

    //开始遍历,输出字段
    for i := 0; i < t.NumField(); i++ {
        //获取属性下标
        f := t.Field(i)
        val := v.Field(i).Interface()
        //输出属性的名称,类型,对应的值
        fmt.Printf("%6s:%v = %v\n", f.Name, f.Type, val)
    }

    //开始获取 方法的基本信息
    for i:=0; i<t.NumMethod(); i++ {
        m := t.Method(i)
        fmt.Printf("%6s:%v\n", m.Name, m.Type)
    }

}

2、反射是如何 获取 匿名字段呢?

//反射 是如何处理 匿名字段的?
package main

import (
    "reflect"
    "fmt"
)

type Stu struct {
    Id int
    Name string
    Age int
}

type Man struct {
    //这里你要注意一下,你创建的属性,是有顺序的,是有下标的
    //如Stu 下标 就是0, title下标就是1
    // Stu 就是匿名属性
    Stu
    title string
}

func main() {
    //注意,对匿名字段进行初始化时的方式,其实本质上跟其他属性是一样的
    m := Man{Stu:Stu{Id:2,Name:"Jack",Age:19}, title:"Manager"}
    t := reflect.TypeOf(m)

    //取匿名字段的方式
    //FieldByIndex 方法,传入的是一个切片slice类型
    //第1个0,表示,匿名字段在Man中的下标位置
    //第2个0,表示,你要取匿名字段中哪个属性的下标
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,0})) //取的是id
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,1})) //取的是Name
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,2})) //取的是Age

}

3、通过反射对基本类型进行修改


//如果通过反射,对基本类型进行修改
package main

import (
    "reflect"
    "fmt"
)

func main() {
    //下面测试,对基本类型的修改 操作
    x := 456
    //传递的参数是  地址
    v := reflect.ValueOf(&x)

    //Elem方法,是取出元素值来,然后通过setint方法,进行重新设置
    v.Elem().SetInt(789)

    fmt.Println(x)
}

4、通过反射 对复杂类型进行修改

//如果通过反射,对复杂类型进行修改
package main

import (
    "reflect"
    "fmt"
)

type Teac struct {
    Id int
    Name string
    Age int
}

func main() {
    teac := Teac{Id:5,Name:"Ant-man",Age:23}
    fmt.Println("teac:\t", teac)
    //传递的是 地址哦
    Set(&teac)
    fmt.Println("teac:\t", teac)
}

func Set(o interface{}) {
    v := reflect.ValueOf(o)
    if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
        fmt.Printf("xxx")
        return
    }else{
        v = v.Elem()
    }

    // 通过FieldByName 这个方法,直接输入 名称,来获取
    f := v.FieldByName("Name")

    //校验,是否取到Name属性的值
    if !f.IsValid() {
        fmt.Printf("BAD")
        return
    }

    //然后,再校验,类型是否匹配
    if f.Kind() == reflect.String {
        f.SetString("Iron Man")
    }

}

5、通过反射对方法进行动态调用

//通过反射,进行方法的调用,相当于动态调用了
package main

import (
    "fmt"
    "reflect"
)

type Teacher struct {
    Id int
    Name string
    Age int
}

//通过receiver将Show方法,跟Teacher类型,进行绑定
func (teacher Teacher)Show(name string) {
    fmt.Println("hello, ", name, ", my name is ", teacher.Name)
}

//注意======目前没有发现====如何通过====反射===来获取=====私有方法
func (teacher Teacher)info(){
    fmt.Println("=====")
}

func main() {
    teacher := Teacher{Id:34, Name:"Thor",Age:34}
    teacher.Show("Hawkeye")

    //下面通过反射,调用show方法
    v := reflect.ValueOf(teacher)
    //获取show方法
    m := v.MethodByName("Show")

    //校验一下,是否获取到show方法呢
    if !m.IsValid() {
        fmt.Printf("=======没有获取到制定的方法====")
        return
    }

    //参数必须是切片类型
    //reflect.Value{}   这里面,可以设定多个参数类型
    //目前,我们这里只有一个string类型的参数
    //
    args := []reflect.Value{reflect.ValueOf("Hulk")}
    m.Call(args)
}

以上是关于Go语言之reflection的主要内容,如果未能解决你的问题,请参考以下文章

Go语言之反射入门

go语言之反射

go语言之数据类型和格式化输出

go语言---reflect

2022-08-19:以下go语言代码输出什么?A:equal;B:not equal;C:不确定。 package main import ( “fmt“ “reflect“ )

go语言的reflect(反射)