Go语言程序设计(十六)反射

        反射(Reflection)是Go语言获取程序运行时类型信息的方式,程序员可以利用这些类型信息进行一些更加灵活的处理工作。Go语言标准库的reflect 包中提供了Typeof()和Valueof()函数,可以使用这两个函数从interface{}接口对象中获取实际目标对象的类型和值信息。
        反射可以大大提高程序开发的灵活性,借助于反射可以让静态语言具备更加多样的运行时动态特征。反射还可以让程序具备自省能力,使得interface{}接口对象的灵活性有更大的发挥余地。

一、获取原对象的Type和Value值

        利用接口反射可以获取对象的Type和Value值。Type 和Value是Go语言reflect包中最重要的两个类型,对所有接口进行反射操作,都可以得到一个包含Type和Value的信息结构。Type 是被反射对象的类型信息,Value是该对象的值信息。可以使用reflect包中Typeof()函数获取被反射对象的类型信息,使用Valueof()函数获取被反射对象的值信息。

        Typeof()和 Valueof()函数的原型定义如下:

func TypeOf(i interface{}) Type
func Value0f(i interface{}) Value

        在操作时,变量类型信息是通过interface{}接口传递给Typeof()函数的,如果调用Typeof(nil)将返回“nil”;变量值信息也是通过interface{}接口传递给ValueOf()函数的,如果调用Typeof(nil)将返回“0”。
        在reflect包中还提供了Type和Value大量的方法,Type的一个非常有用的方法是kind(),这个方法可以返回该类型的具体信息,比如int、int8、float64等。Value 则包含一系列同类型相关的方法,比如int()、float()、bool()等,用于返回对应类型的值。

        Go语言除了能对最基本的数据类型进行反射操作,还能够对结构体进行反射操作。反射操作可以获取结构体各字段的类型信息和值信息,也可以获取结构体对象的方法信息。

当定义结构体字段名和方法名时要注意,这些名字的首写字母一定要大写,否则反射操作时编译器会报错。
        另外,反射会将匿名字段当作一个独立字段来处理,如果要获取嵌入字段的Type和.Value信息,必须使用索引路径来完成。通过Value类型的FieldByIndex()方法可以获取嵌入字段的索引路径,FieldByIndex()方法的原型定义如下:

func (v Value) FieldByIndex( index [ ]int) Value

        FieldByIndex()方法成功执行会返回嵌入字段的索引路径,如果对一个非Struct 类型执行FieldByIndex()方法则会产生panic错误事件。

二、修改原对象Value值

在Go语言中,要利用反射修改原数据对象的前提是该对象是“可修改属性(Settability)”的。可以使用CanSet()方法判断一个对象是否可修改属性,CanSet()方法的原型定义如下:

func (v Value) CanSet() bool

        如果一个对象的Value值可修改,CanSet()方法返回“true”,进而就可以调用Set()方法或SetXxx()方法修改对象的Value值(例如SetInt()、SetBool()、SetFloat()等);如果对象的Value值不可修改,则CanSet()方法返回“false",并产生panic错误事件。
        还有一点需注意的是,在Go语言中所有类型是值类型,即这些变量在传递给函数时将发生一次复制,所以在函数中只能对变量的副本进行修改。要想在函数中对变量本身进行修改,必须使用引用类型,即指针。所以要使用反射修改原对象的值,在使用interface{}接口进行传递时,这个interface{}必须是指针类型的。另外,要想操作目标对象,还要使用Elem()方法进一步获取指针指向的实际目标。

三、动态调用原对象方法

        在reflect包中提供了Call()方 法可以用于调用原对象的方法。Call()的原型定义如下:

func (v Value) Call(in [ ]Value) [ ]Value

        Call()方法可以向原对象传递参数列表并调用它,例如:

if len(in) == 3{
    v.Call(in)
}

        该例中Call()调用了原对象v的方法,并向其传递了三个参数: in[0]、in[1]和in[2]。如果调用成功,将返回正常输出结果;如果调用的是一个非方法类型,则Call()会引发panic错误事件。
        一个原对象通常会有多个方法,那怎样才能调用到指定的方法呢?可以使用reflect 包中的MethodByName()方法来获取想要的方法的Value值,MethodByName()的原型定义如下:

func (v Value) MethodByName( name string) Value

        MethodByName()方法使用原对象的方法名(name)获取该方法的Value值,如果所访问的方法不存在,MethodByName()会返回“0”。
        最后还需注意的是,在Go语言中传递给方法的参数要和方法定义的参数类型保持一致。另外,为了处理变参这种复杂情况,传递给被调用方法的参数通常首先被保存在一个Slice中,然后再复制到参数列表中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值