Golang入门——反射包

方法和类型的反射

反射时用程序检查其所拥有的结构,是元编程的一种形式。反射可以在运行时检查类型和变量。除非真的有必要,否则应尽量避免或小心使用。
反射包中的两个简单函数:

  • reflect.TypeOf( i interface{ }) :返回被检查对象的类型
  • reflect.ValueOf( i interface{ }) :返回被检查对象的数值
var x float64 = 3.14  
fmt.Println(reflect.TypeOf(x))  
fmt.Println(reflect.ValueOf(x))

输出结果:

float64
3.14

此外,我们可以使用 Kind( ) 方法来识别 reflect.ValueOf( ) 的返回的数据类型。如果x的数值类型为Float64,则reflect.ValueOf(x).Kind( ) == reflect.Float64。

fmt.Printf("%t",reflect.Float64==v.Kind())

输出结果:

true

Kind( ) 方法总是返回底层类型。

type MyInt int  
var myint MyInt = 5
fmt.Println(reflect.TypeOf(myint))  
fmt.Println(reflect.ValueOf(myint).Kind())

输出结果:

main.MyInt
int

通过输出结果可以看到 reflect.TypeOf( ) 返回的为变量声明时使用的类型,而 Kind( ) 方法返回的为变量声明时使用类型的底层类型。

使用 Interface( )方法可以得到还原值

fmt.Printf("%v,%[1]T\n%v,%[2]T",v,v.Interface())  
fmt.Println(v.Interface()==reflect.Float64)

输出结果:

3.14,reflect.Value
3.14,float64
false

Interface( )方法可以将reflect.ValueOf( ) 函数的返回值从Value类型转换为原始类型。使用Float( )、Int( )、String( )、Bool( )等方法同样可以实现相同的功能。

fmt.Printf("%v,%[1]T\n",v.Float())

输出结果:

3.14,float64

通过反射修改值

使用SetFloat( )的方法可以实现修改数值,使用时必须小心,如果该变量不可设置,则会出现报错。可以使用CanSet( )方法来测试是否可设置。CanSet( )方法的返回值为False,可使用Elem( )方法使其成为可设置的状态。使用Elem方法之前需要获取指针。

var Num float64= 3.15  
Value := reflect.ValueOf(Num)  
if ok := Value.CanSet(); ok {  
	fmt.Println("Value Can Set")  
	Value.SetFloat(4.56)  
}else{  
	fmt.Println("Value Cannot Set, Now Elem it")  
	Value := reflect.ValueOf(&Num)  
	Value = Value.Elem()  
	fmt.Println("The CanSet Is ", Value.CanSet())  
	Value.SetFloat(1.23)  
}  
fmt.Println(Value)

输出结果:

Value Cannot Set, Now Elem it
The CanSet Is  true
3.15

一定注意在使用Elem方法之前重新使用reflect.ValueOf(&Num)

反射结构

有些时候需要反射一个结构类型。NumField( )方法返回结构内的字段数。通过一个 for 循环用索引取得每个字段的值 Field( i )。我们同时能够调用签名在结构上的方法,可以使用索引来调用 Method( n ).Call( nil )。

type ThreeString struct{  
	s1,s2,s3 string  
}  
func (s ThreeString)String() string{  
	return s.s1 + "-" + s.s2 + "-"+s.s3  
}  
var secret interface{}=ThreeString{"Alpha","Bete","Omega"}
func main(){
	Value1 := reflect.ValueOf(secret)  
	Type1 := reflect.TypeOf(secret)  
	fmt.Println(Type1)  
	fmt.Println(Value1.Kind())  
	for i := 0 ; i < Value1.NumField() ; i++ {  
	  fmt.Printf("Field %d : %v\n",i,Value1.Field(i))  
	}  
	fmt.Println(Value1)  
	results := Value1.Method(0).Call(nil)  
	fmt.Println(results)
}

输出结果:

main.ThreeString
struct
Field 0 : Alpha
Field 1 : Bete
Field 2 : Omega
Alpha-Bete-Omega
[Alpha-Bete-Omega]

但是如果使用Field( n ).SetString( ) 方法来改变一个值会出现错误:

panic: reflect: reflect.Value.SetString using value obtained using unexported field

因为结构中只有被导出字段(首字母大写)才是可设置的:

type T struct {  
	A int  
	B string  
}
func main() {
	t := T{23,"skidoo"}  
	s := reflect.ValueOf(&t).Elem()  
	typeOfT := s.Type()  
	for i := 0 ; i < s.NumField() ; i++{  
		f := s.Field(i)	
		fmt.Printf("%d:%s %s = %v \n", i, typeOfT.Field(i).Name , f.Type(),f.Interface())  
	}  
	s.Field(0).SetInt(77)  
	s.Field(1).SetString("Sunset Strip")  
	fmt.Println("t is now :",t)
}

输出结果:

0:A int = 23
1:B string = skidoo
t is now : {77 Sunset Strip}

代码下载

以上程序代码均已上传到至github ,有需要可直接进行下载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值