反射讓我們可以在運行時獲取對象的類型信息,比如查看一個結構體有多少字段,查看函數的入參類型和返回值類型等。
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))
}
}