反射让我们可以在运行时获取对象的类型信息,比如查看一个结构体有多少字段,查看函数的入参类型和返回值类型等。
Go提供了reflect.TypeOf()和reflect.ValueOf获取任意对象的reflect.Value和reflect.Type,其中reflect.Type是一个接口类型,该接口提供了很多方法让我们获取类型信息,而reflect.Value是一个结构体,它提供了很多方法让我们获取或者写入reflect.Value结构体中存储的数据。
获取类型信息
package main
import (
"fmt"
"reflect"
)
type Person struct {
name string
height int
}
func (person Person) AddHeight(height int) string{
person.height+=height
return string(person.height)
}
func main(){
//遍历结构体字段
person:=Person{}
valueType:=reflect.TypeOf(person)
for i:=0;i<valueType.NumField();i++{
field:=valueType.Field(i)
fmt.Println(field.Name,field.Type)
}
//遍历结构体导出的方法
for i:=0;i<valueType.NumMethod();i++{
method:=valueType.Method(i)
fmt.Println(method.Name)
}
//遍历函数参数和返回值
valueType=reflect.TypeOf(Person{}.AddHeight)
for i:=0;i<valueType.NumIn();i++{
arg:=valueType.In(i)
fmt.Println(arg)
}
for i:=0;i<valueType.NumOut();i++{
result:=valueType.Out(i)
fmt.Println(result)
}
}
底层类型
使用Kind方法可以获取类型的底层类型,Go提供了以下底层类型:
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
通过reflect.Value还原对象
使用Interface()方法可以将reflect.Value还原成接口类型,然后再强转一次就能还原成原本的类型。
func main(){
value := reflect.ValueOf(1)
fmt.Println(value.Interface().(int))
}
通过reflect.Value修改对象
如果想通过reflect.Value修改对象,那么reflect.ValueOf()需要传递对象的地址,然后通过Elem()方法找到这个指针指向的值才能修改,reflect.Value提供了CanSet()方法帮助我们判断是否可以修改该对象。
func main(){
name:="xiongya"
nameValue:=reflect.ValueOf(&name)
nameValue.Elem().SetString("xy")
fmt.Println(name)
}
动态调用方法
利用反射动态调用方法时参数和返回值都是reflect.Value切片。
package main
import (
"fmt"
"reflect"
"strconv"
)
type Person struct {
name string
height int
}
func (person Person) AddHeight(height int) string{
person.height+=height
return strconv.Itoa(person.height)
}
func main(){
person:=Person{"xiao hong",100}
value:=reflect.ValueOf(person)
method:=value.MethodByName("AddHeight")
if method.IsValid(){
args:=[]reflect.Value{reflect.ValueOf(10)}
fmt.Println(method.Call(args))
}
}
有疑问加站长微信联系(非本文作者)