內(nèi)容
1 獲取接口類型值
2 修改接口類型值
3 反射調(diào)用函數(shù)
4 反射調(diào)用方法
5 reflect包api使用
先回顧一下反射三大定律:
1 反射可以將“接口類型變量”轉(zhuǎn)換為“反射類型對象”;
2 反射可以將“反射類型對象”轉(zhuǎn)換為“接口類型變量”;
3 如果要修改“反射類型對象”腾供,其值必須是“可寫的”(settable)。
一 反射獲取接口類型值
通過接口變量獲取變量指向的值和類型信息:
1 先通過接口變量獲取value反射對象
2 通過value的Interface可以獲取接口變量指向的對象暑始,是interface類型
3 斷言獲取接口值
4 通過value對象type()方法獲取接口變量的類型信息,是靜態(tài)類型信息
5 通過type對象獲取接口變量的種類信息烫止,是具體的基本類型信息蒋荚,如:int slice func map string等基礎(chǔ)類型,在reflect/type有所有的基礎(chǔ)類型kind
type MyType int
func main() {
var i = MyType(1)
iValue := reflect.ValueOf(i)
iType := reflect.TypeOf(i)
fmt.Printf(" i value: %v", iValue.Interface()) // i value: 1
fmt.Printf(" i type: %v", iValue.Type()) // i type: main.MyType
fmt.Printf(" i kind: %v", iType.Kind()) // i kind: int
}
// 獲取結(jié)構(gòu)體字段信息
// 結(jié)構(gòu)體包含不可導(dǎo)出字段s馆蠕,此時反射獲取這個不可導(dǎo)出字段時期升,會panic
func reflectGetStructField() {
m := MyStruct{
A: 1,
B: true,
s: "test",
}
mValue := reflect.ValueOf(m)
mType := reflect.TypeOf(m)
for i:=0; i < mValue.NumField(); i++ {
v := mValue.Field(i)
fmt.Printf(" field: %v {type: %v; value:%v}", mType.Field(i).Name,
v.Type(), v.Interface())
}
}
//panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
// 將s調(diào)整為S
輸出:
field: A {type: int; value:1} field: B {type: bool; value: true} field: S {type: string; value: test}
二 修改接口類型值
要修改接口類型值,要謹(jǐn)記反射第三定律互躬,其值要是可寫的
總結(jié)為:
1 根據(jù)接口指針變量獲取value對象播赁;
2 根據(jù)Elem方法value變量具體指向的數(shù)據(jù);
3 可以根據(jù)value對象的CanSet方法判斷是否可寫吼渡;
4 調(diào)用value對象的SetX方法進(jìn)行改變容为;
func reflectModifyStructField() {
m := MyStruct{
A: 1,
B: true,
S: "test",
}
mValue := reflect.ValueOf(&m).Elem()
// 以下兩種都是不行的,獲取接口指針變量的value對象后寺酪,一定要調(diào)用Elem()方法解引用獲取指向的具體數(shù)據(jù)坎背,
// 因為我們對具體數(shù)據(jù)域修改,不是對mValue這個value 類型變量修改寄雀;
// 1 mValue := reflect.ValueOf(&m)
// 2 mValue := reflect.ValueOf(m)
mType := reflect.TypeOf(&m)
fmt.Println(fmt.Sprintf("%v can set: %v", mType, mValue.CanSet()))
for i:=0; i < mValue.NumField(); i++ {
if mValue.Field(i).Kind() == reflect.String {
mValue.Field(i).SetString("new test")
}
}
fmt.Println(fmt.Sprintf("%v : %v", mType, m))
}
// 輸出:
*main.MyStruct can set: true
*main.MyStruct : {1 true new test}
三 反射調(diào)用函數(shù)
1 獲取方法對象變量
2 獲取value反射對象
3 構(gòu)造方法入?yún)lice, reflect.Value切片
4 調(diào)用value Call方法
5 得到執(zhí)行結(jié)果得滤,是value 切片
func Add(i, j int) int {
return i + j
}
func main() {
a := Add
aValue := reflect.ValueOf(a)
aParam := make([]reflect.Value, 2)
aParam[0] = reflect.ValueOf(1)
aParam[1] = reflect.ValueOf(2)
fmt.Println("reflect exe add, result: ", aValue.Call(aParam)[0])
}
// 輸出
reflect exe add, result: 3
四 反射調(diào)用方法
1 獲取value對象
2 構(gòu)造方法入?yún)lice, reflect.Value切片
3 根據(jù)MethodByName()獲取方法value對象
4 調(diào)用call方法執(zhí)行
type MyStruct struct {
A int
B bool
S string
}
func (m *MyStruct) Subtract(i, j int) int {
return i - j
}
func main() {
m := MyStruct{}
aParam := make([]reflect.Value, 2)
aParam[0] = reflect.ValueOf(1)
aParam[1] = reflect.ValueOf(2)
//方法是指針接收器,這里必須是指針變量
mValue := reflect.ValueOf(&m)
aParam[0] = reflect.ValueOf(1)
aParam[1] = reflect.ValueOf(2)
fmt.Println("reflect MyStruct Subtract, result: ", mValue.MethodByName("Subtract").Call(aParam)[0])
}
// 輸出
reflect MyStruct Subtract, result: -1
五 reflect包api使用
1 創(chuàng)建slice map chan
// 反射創(chuàng)建map slice channel
intSlice := make([]int, 0)
mapStringInt := make(map[string]int)
sliceType := reflect.TypeOf(intSlice)
mapType := reflect.TypeOf(mapStringInt)
// 創(chuàng)建新值
intSliceReflect := reflect.MakeSlice(sliceType, 0, 0)
mapReflect := reflect.MakeMap(mapType)
// 使用新創(chuàng)建的變量
v := 10
rv := reflect.ValueOf(v)
intSliceReflect = reflect.Append(intSliceReflect, rv)
intSlice2 := intSliceReflect.Interface().([]int)
fmt.Println(intSlice2)
k := "hello"
rk := reflect.ValueOf(k)
mapReflect.SetMapIndex(rk, rv)
mapStringInt2 := mapReflect.Interface().(map[string]int)
2 創(chuàng)建函數(shù)
使用reflect.Makefunc()創(chuàng)建函數(shù)盒犹,入?yún)⑹牵合胍獎?chuàng)建的函數(shù)的reflect.type和一個輸入?yún)?shù)是[] reflect.value類型的slice懂更,其輸出參數(shù)也是類型reflect.value 切片的閉包
package main
import (
"reflect"
"time"
"fmt"
"runtime"
)
/*
將創(chuàng)建Func封裝眨业, 非reflect.Func類型會panic
當(dāng)然makeFunc的閉包函數(shù)表達(dá)式類型是固定的,可以查閱一下文檔沮协。
細(xì)讀文檔的reflect.Value.Call()方法龄捡。
*/
func MakeTimedFunction(f interface{}) interface{} {
rf := reflect.TypeOf(f)
if rf.Kind() != reflect.Func {
panic("非Reflect.Func")
}
vf := reflect.ValueOf(f)
wrapperF := reflect.MakeFunc(rf, func(in []reflect.Value) []reflect.Value {
start := time.Now()
out := vf.Call(in)
end := time.Now()
fmt.Printf("calling %s took %v\n", runtime.FuncForPC(vf.Pointer()).Name(), end.Sub(start))
return out
})
return wrapperF.Interface()
}
func time1() {
fmt.Println("time1Func===starting")
time.Sleep(1 * time.Second)
fmt.Println("time1Func===ending")
}
func time2(a int) int {
fmt.Println("time2Func===starting")
time.Sleep(time.Duration(a) * time.Second)
result := a * 2
fmt.Println("time2Func===ending")
return result
}
func main() {
timed := MakeTimedFunction(time1).(func())
timed()
timedToo := MakeTimedFunction(time2).(func(int) int)
time2Val := timedToo(5)
fmt.Println(time2Val)
}
引用文檔:Golang Reflect反射的使用詳解1 https://my.oschina.net/90design/blog/1614820