理解反射
反射如同鏡子昂验,可以反射實(shí)體物品的模樣;如:豬八戒照鏡子里外都是豬,因?yàn)殓R子反射的就是照鏡子的對(duì)象
三大法則
- 反射的第一法則是我們能將 Go 語(yǔ)言的 interface{} 變量轉(zhuǎn)換成反射對(duì)象
package main
import (
"fmt"
"reflect"
)
func main() {
a := 10
fmt.Println("TypeOf : a :", reflect.TypeOf(a))
fmt.Println("ValueOf : a :", reflect.ValueOf(a))
}
- 反射的第二法則是我們可以從反射對(duì)象可以獲取 interface{} 變量
package main
import (
"fmt"
"reflect"
)
a := 9
rv := reflect.ValueOf(a)
rvi := rv.Interface().(int) // rv.Interface() 返回是Interface{}類型,后續(xù)為斷言
fmt.println(rvi)
- 反射的第三法則是可以進(jìn)行原值的修改
package main
import (
"fmt"
"reflect"
)
a := 9
rv := reflect.ValueOf(&a)
rv.Elem().SetInt(100)
fmt.Println(a) // 100
使用場(chǎng)景
- 類型判斷
- 動(dòng)態(tài)調(diào)用函數(shù)
反射無(wú)法獲取方法的注釋,簡(jiǎn)單來(lái)講是因?yàn)間olang編譯時(shí)芒帕,沒有把注釋編譯進(jìn)去,所以也無(wú)法通過反射獲取到充包。類比php中ReflectClass能獲取到成員函數(shù)對(duì)應(yīng)的注釋副签,可以用來(lái)做權(quán)限配置說明遥椿、api文檔生成等。
Demo
package main
import (
"fmt"
"reflect"
"strings"
"sync"
)
type Task struct {
}
var wg sync.WaitGroup
func main() {
fmt.Println("======================")
testType()
testFun()
testEqual()
testStruct()
testTypeOf()
fmt.Println("======================")
}
// 方法反射
// 反射將“接口類型的變量”轉(zhuǎn)為了“反射的接口類型的變量”
func testFun() {
// 獲取要運(yùn)行的task
task := "TestRun,TestRun1"
taskArr := strings.Split(task, ",")
l := len(taskArr)
wg.Add(l)
for _, taskMethod := range taskArr {
go InvokeObjectMethod(new(Task), taskMethod, "arg1", "arg2")
}
wg.Wait()
fmt.Println("======================")
}
// 類型與值都相等
func testEqual(){
type myInt int
var a myInt = 1
b := 1
res := reflect.DeepEqual(a, b)
fmt.Printf("a == b ? %v\n", res)
fmt.Println("======================")
}
// 變量反射
func testType(){
var myType string = "字符串"
t := reflect.TypeOf(myType).Name()
v := reflect.ValueOf(myType)
fmt.Println("type", t)
fmt.Println("value", v)
fmt.Println("======================")
}
// 結(jié)構(gòu)體反射
type PhpClass struct {
phpId int
phpName string
}
func (p PhpClass) PhpFun() {
fmt.Println("PhpClass 的 PhpFun淆储, 注意方法名大寫開頭才可以")
}
func (p PhpClass) phpFunTest() {
fmt.Println("PhpClass 的 phpFunTest冠场, 小寫反射不出來(lái)")
}
func testStruct(){
p := PhpClass{
phpId: 110,
phpName: "phper",
}
t := reflect.TypeOf(p)
v := reflect.ValueOf(p)
for i := 0; i < t.NumField(); i++ {
// 從0開始獲取Student所包含的key
key := t.Field(i)
// 通過interface方法來(lái)獲取key所對(duì)應(yīng)的值
value := v.Field(i)
fmt.Printf("第%d個(gè)字段是:%s:%v = %v \n", i+1, key.Name, key.Type, value)
}
for i := 0; i < t.NumMethod(); i++ {
fun := t.Method(i)
fmt.Printf("第%d個(gè)方法是:%s:%v\n", i+1, fun.Name, fun.Type)
}
fmt.Println("======================")
}
// 通過反射對(duì)比類型
func testTypeOf(){
s := PhpClass{}
t := reflect.TypeOf(s)
// 通過.Kind()來(lái)判斷對(duì)比的值是否是struct類型
if k := t.Kind(); k == reflect.Struct {
fmt.Println("是struct類型")
}
num := 1
numType := reflect.TypeOf(num)
if k := numType.Kind(); k == reflect.Int {
fmt.Println("是int類型")
}
str := "string"
st := reflect.TypeOf(str)
if k := st.Kind(); k == reflect.String {
fmt.Println("是string類型")
}
fmt.Println("======================")
}
func InvokeObjectMethod(object interface{}, methodName string, args ...interface{}) {
defer wg.Done()
inputs := make([]reflect.Value, len(args))
for i := range args {
inputs[i] = reflect.ValueOf(args[i])
}
if v := reflect.ValueOf(object).MethodByName(methodName); v.String() == "<invalid Value>" {
fmt.Println("【反射調(diào)用錯(cuò)誤:object:", object, " | methodName:", methodName, " --> <invalid Value>】")
} else {
fmt.Println("【反射調(diào)用成功:object:", object, " | methodName:", methodName, "|v.String():", v.String(), "】")
v.Call(inputs)
}
}
func (t *Task) TestRun(arg... interface{}) {
fmt.Println("測(cè)試反射調(diào)用方法 - TestRun", arg)
}
func (t *Task) TestRun1(arg... interface{}) {
fmt.Println("測(cè)試反射調(diào)用方法 - TestRun1", arg)
}