Golang反射的使用
阿新 • • 發佈:2019-01-12
反射的基本介紹:
1)反射可以在執行時動態獲取變數的各種資訊,比如變數的型別(type),類別(kind)
2)如果是結構體變數,還可以獲取到結構體本身的資訊(包含結構體的欄位、方法)
3)通過反射,可以修改變數的值,可以呼叫關聯的方法。
型別的相互轉換:
例項1:
package main import ( "fmt" "reflect" ) type student struct { Name string Age int } //修改簡單資料型別 func changeData(i interface{}) { value := reflect.ValueOf(i) fmt.Println("kind:", value.Kind()) value.Elem().SetInt(30) } //修改結構體型別資料 func ModityData(i interface{}) { value := reflect.ValueOf(i) fmt.Println(value.Kind()) value.Elem().Field(0).SetString("江洲你好!") value.Elem().Field(1).SetInt(33333) } //通過反射 改變結構體對應欄位的值 func main() { stu := student{Name: "jiangzhou", Age: 23} fmt.Println("原資料為:", stu) ModityData(&stu) fmt.Println("通過反射改變資料之後的值為:", stu) } //通過反射改變基本資料型別的值 func main02() { num := 10 fmt.Println("原來資料是:", num) changeData(&num) fmt.Println("改變之後的資料是:", num) } //反射的基本使用: 型別 value 以及value與資料的相互轉換 func main01() { stu := student{Name: "jiangzhou", Age: 23} typeOf := reflect.TypeOf(stu) fmt.Println(typeOf, typeOf.Kind()) fmt.Println("執行value操作") value := reflect.ValueOf(stu) fmt.Println(value) interface1 := value.Interface() stu1 := interface1.(student) fmt.Println(stu1, stu1.Name, stu1.Age) }
例項2:
package main import ( "fmt" "reflect" ) /* 主要功能:1、取出結構體 tag中json對應的內容 */ type Stu struct { Name string `json:"name"` Age int `json:"age"` Address string `json:"address"` } func(s Stu) Print1() { fmt.Println(s.Name,s.Age,s.Address) } func (s Stu)Update1 () { s.Address="重慶" s.Age+=1 } func (s Stu)GetNum(n1 ,n2 int) int { return n1+n2 } func showTag(i interface{}) { if reflect.TypeOf(i).Kind()!=reflect.Struct { fmt.Println("不是結構體型別 ") return } varlue:=reflect.ValueOf(i) type1:=reflect.TypeOf(i) num:=varlue.NumField() for i:=0;i<num;i++{ fmt.Print("結構體第",i,"個欄位為:",varlue.Field(i)) tag:=type1.Field(i).Tag //獲取標籤 fmt.Println("\t",tag,tag.Get("json")/*獲取json對應的便籤*/) } fmt.Println("執行方法的呼叫") num1 := varlue.NumMethod() //標記:方法名一定要大寫,不然會找不到對應的方法 fmt.Println("結構體方法的個數為:",num1) varlue.Method(1).Call(nil) args:=[]reflect.Value{reflect.ValueOf(10),reflect.ValueOf(20)} call := varlue.Method(0).Call(args) fmt.Println(call[0].Int()) fmt.Println("通過斷言來執行的操作:") i2 := call[0].Interface() res,ok:=i2.(int) fmt.Println(res,ok) } func main() { stu:=Stu{Name:"jiangzhou",Age:23,Address:"cq"} showTag(stu) }
例項3
以下例項為測試用例(golang自帶了測試框架,測試檔案命名規則:XX_test.go。如以下例項的檔名稱為:refelect_test.go;測試方法名稱命名規則為:TestXxx,以下測試方法名稱為:TestReflectFunc)
package main import ( "testing" ) func TestReflectFunc(t *testing.T) { call1:= func(v1 int,v2 int) { t.Log(v1,v2) } call2:= func(v1 int,v2 int,s string) { t.Log(v1,v2,s) } call1(1,2) call2(1,2,"call2") }
通過反射完成測試方法的呼叫:
package main
import (
"reflect"
"testing"
)
func TestReflectFunc(t *testing.T) {
call1:= func(v1 int,v2 int) {
t.Log(v1,v2)
}
call2:= func(v1 int,v2 int,s string) {
t.Log(v1,v2,s)
}
var (
function reflect.Value
inValue []reflect.Value
n int
)
bridge:= func(call interface{},args ...interface{}) {
n=len(args)
inValue=make([]reflect.Value,n)
for i:=0;i<n;i++{
inValue[i]=reflect.ValueOf(args[i])
}
function=reflect.ValueOf(call)
function.Call(inValue)
}
bridge(call1,1,2)
bridge(call2,1,2,"call2")
}
不知道介面 呼叫那個 函式,根據傳入引數在執行時確定呼叫的具體介面,這種需要對函式或方法反射。如以上這種橋接模式:
bridge:= func(call interface{},args ...interface{}){...}
第一個引數call以介面的形式傳入函式指標,函式引數args以可變引數的形式傳入,bridge函式中可以用反射來動態執行call函式。
例項4
package main
import (
"encoding/json"
"fmt"
)
type Stu1 struct {
Name string `json:"stuName"`
Age int `json:"stuAge`
Address string `json:"StuAddress"`
}
func main() {
stu:=Stu1{Name:"jiangzhou",Age:23,Address:"cq"}
data,_:=json.Marshal(stu)
fmt.Println(string(data))
}
對結構體序列化時,如果結構體有指定Tag,goland底層也會使用到反射生成對應的字串。