为了账号安全,请及时绑定邮箱和手机立即绑定

Go语言之reflection

标签:
JavaScript

reflection 反射

  • 反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地

  • 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息

  • 反射会将匿名字段作为独立字段(匿名字段本质)

  • 想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface

  • 通过反射可以"动态"调用方法


举例

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

//反射  练习//获取字段的类型信息,方法信息, 属性信息package mainimport (    "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 mainimport (    "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 mainimport (    "reflect"    "fmt")func main() {    //下面测试,对基本类型的修改 操作    x := 456    //传递的参数是  地址    v := reflect.ValueOf(&x)    //Elem方法,是取出元素值来,然后通过setint方法,进行重新设置    v.Elem().SetInt(789)    fmt.Println(x)}

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

//如果通过反射,对复杂类型进行修改package mainimport (    "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 mainimport (    "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)}

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消