非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第14章 反射
- 14.2 基本用法
- 14.2.2 获取类型的值
- 14.2.3 使用反射调用函数
第14章 反射
14.2 基本用法
14.2.2 获取类型的值
Go语言使用reflect.TypeOf来获取类型信息,使用reflect.ValueOf来获取变量值的信息。
reflect.ValueOf()函数可以获取值的反射值对象(reflect.Value),使用方法如下:
var valueOfNum reflect.Value = reflect.ValueOf(num)
reflect.Value是反射中非常重要的类型,获取变量的值和反射调用函数都需要使用该类型。
reflect.Value有一系列的获取变量值的方法,例如Int()方法用来获取int类型变量的值,如果用此函数获取其他Kind(非Int、Int8、Int16、Int32、Int64类型变量)的值将会引发panic。
[ 动手写 14.2.3 ]
package main
import (
"fmt"
"reflect"
)
func checkValue(v reflect.Value) {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Int {
// 方法一
var v1 int = int(v.Int())
// 方法二
var v2 int = v.Interface().(int)
fmt.Println(v1, v2)
}
}
func main() {
var num int = 10
valueOfNum := reflect.ValueOf(num)
fmt.Println("valueOfNum")
checkValue(valueOfNum)
valueOfNumPtr := reflect.ValueOf(&num)
fmt.Println("valueOfNumPtr")
checkValue(valueOfNumPtr)
}
动手写14.2.3使用int类型变量为例子,函数checkValue()依旧会对指针类型变量做特殊处理,使用两个方法获取变量num的值,一个是使用上面介绍的Int()函数获取,再从reflect.Value类型强制转换成int类型数据,另一个是使用Interface()方法转换成Interface{}类型,再从Interface{}类型转换成int类型数据。
运行结果如下:
14.2.3 使用反射调用函数
使用反射调用函数需要用到reflect.ValueOf()方法传入想要反射的函数名,获取到reflect.Value对象,再通过reflect.Value对象的Call方法调用该函数,Call方法的声明如下:
func (v Value) Call(in []Value) []Value
Call方法使用输入的参数in调用v持有的函数。例如,如果len(in) == 3,v.Call(in)代表调用v(in[0], in[1], in[2])(其中Value值表示其持有值)。
如果v的Kind不是Func会引发panic。它返回函数所有输出结果的Value封装的切片。和Go代码一样,每一个输入实参的持有值都必须可以直接赋值给函数对应输入参数的类型。
如果v持有值是可变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面。
[ 动手写 14.2.4]
package main
import (
"fmt"
"reflect"
)
func Equal(a, b int) bool {
if a == b {
return true
}
return false
}
func main() {
// 反射调用函数需使用 ValueOf
valueOfFunc := reflect.ValueOf(Equal)
// 构造函数参数
args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
// 通过反射调用函数计算
result := valueOfFunc.Call(args)
fmt.Println("函数运行结果: ", result[0].Bool())
}
动手写14.2.4定义了一个Equal函数,Equal函数传入参数a、b判断两个值是否相等,返回对应结果。
主函数使用reflect.ValueOf获取reflect.Value对象,并构造了参数args传入Call函数中,运行结果如下:
【懂了!!】