• 一、Golang中的反射基本使用


      Go中也提供了反射机制,与Java一样Go的反射也是在运行时获取对象的相关信息,更新对象内部状态;Golang通过反射可以获取对象类型、字段类型与值、调用struct实例方法、更新实例值等;
      Go关于反射相关的对象、函数都在reflect包中最主要的两个为:Type与Value;
      Go提供了下面两个函数,这两个是Go反射的核心;
      reflect.TypeOf 返回目标对象的类型
      reflect.ValueOf 返回值目标对象的值

    t:=1
    fmt.Println(reflect.TypeOf(t), reflect.ValueOf(t))
    输出:int 1
    

    通过反射操作Struct

    type Demo struct {
      Id   int
      Name string
    }
    func (d *Demo) Back() {
        fmt.Println("调用方法 Back")
    }
    func (d *Demo) Add(a, b int) int {
    	return a + b
    }
    

    获取结构体中每个成员变量的名称与值:

     d := &Demo{Id: 2, Name: "test"}
     getValue(d)
     输出: Id :  2
          Name :  test
    
    func getValue(v interface{}) {
    	t := reflect.TypeOf(v)
    	o := reflect.ValueOf(v)
    	if t.Kind() == reflect.Ptr {
    		t = t.Elem()   //获取类型指针中的类型
    	}
    	if o.Kind() == reflect.Ptr {
    		o = o.Elem()  //获取值地址中的值
    	}
    	num := t.NumField()  //获取字段个数
    	for i := 0; i < num; i++ {
    		f := o.Field(i)     //获取字段的值
    		fieldName := t.Field(i).Name  //获取字段名称
    		switch f.Kind() {
    		case reflect.Int:
    			fmt.Println(fieldName, ": ", f.Int()) 
    		case reflect.String:
    			fmt.Println(fieldName, ": ", f.String())
    		default:
    			fmt.Println("类型不不支持")
    		}
    	}
    }
    

      对于引用类型使用reflect.TypeOf返回的是该类型的指针,reflect.ValueOf返回的是该类型的值地址;所以对于引用类型都要的相关操作都要调用Elem()函数获取真实的类型与值;
      调用Type或Value对象的NumField函数获取结构体的字段个数
      调用Value对象的Field(i) 可获取字段的值;
      调用Value对象的Kind()函数可获取字段的类型;
      该Value对应于哪种类型调用对应的函数即可获取得到相应的值,如类型不一致将抛出:panic: reflect: call of reflect.Value.Xxx on int Value;

    修改结构体中每个成员变量的值:

        d := new(Demo)
        setValue(d)
        fmt.Println(d)
        输出:&{88 Test}
    
        func setValue(v interface{}) {
    	t := reflect.TypeOf(v)
    	o := reflect.ValueOf(v)
    	if t.Kind() == reflect.Ptr {
    		t = t.Elem()
    	}
    	if o.Kind() == reflect.Ptr {
    		o = o.Elem()
    	}
    	num := t.NumField()
    	for i := 0; i < num; i++ {
    		f := o.Field(i)
    		switch f.Kind() {
    		case reflect.Int:
    			f.SetInt(88)    //往该字段设值
    		case reflect.String:
    			f.SetString("Test") /往该字段设值
    		default:
    			fmt.Println("类型不支持")
    		}
    	}
        }
    

      修改字段值与获取值一样,类型一定要一致,如不一致将抛异常,如int类型却调用SetString设值:panic: reflect: call of reflect.Value.SetString on int Value;

    调用结构体的无参方法:

    d := new(Demo)
    callMethod(d) 
    输出:调用方法 Back
    
    func callMethod(v interface{}) {
    	o := reflect.ValueOf(v)
    	o.MethodByName("Back").Call(nil)
    }
    

      调用MethodByName根据名称获取方法,Call调用该方法;

    调用结构体的有参方法:

    d := new(Demo)
    callMethodParam (d) 
    输出:3
    
    func callMethodParam(p interface{}) {
    	o := reflect.ValueOf(p)
    	args:=[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
    	v:= o.MethodByName("Add").Call(args)
    	fmt.Println(v[0])
    }
    

      比较常用的方法还有:
      使用名字获取结构体的成员
    Refletct.ValueOf(*e).FieldByName(“Name”)
      获取结构体成员的json标记信息
    reflect.TypeOf(s) . Field(0).Tag.Get(“key”)

      Golang的反射也遵循Go语言规则,反射无法修改结构体中的私有对象,无法调用私有私有方法,可访问私有成员,修改私有成员将会抛出reflect.flag.mustBeAssignable异常;

    文章首发地址:Solinx
    https://mp.weixin.qq.com/s/W0UVbFxMMeXA5HuNNZlK-A

  • 相关阅读:
    SpringCloud整合过程中jar依赖踩坑经验
    spring-boot-starter-parent的主要作用
    配置Setting.xml文件提高maven更新下载jar包速度
    剑指Offer-编程详解-二维数组中的查找
    Git 拉取Gitee仓库报错:“fatal: unable to access ''": Failed to connect to 127.0.0.1 port 1080: Connection refused”
    SpringBoot整合mybatis——配置mybatis驼峰命名规则自动转换
    SpringBoot 整合 Mybatis + Mysql——XML配置方式
    ES+open-falcon之nginx状态码监控报警自动化
    zabbix告警邮件美化
    基于Jenkins+Gitlab的自动化部署实战
  • 原文地址:https://www.cnblogs.com/softlin/p/12920032.html
Copyright © 2020-2023  润新知