??Go中也提供了反射機制,與Java一樣Go的反射也是在運行時獲取物件的相關資訊,更新物件內部狀態;Golang通過反射可以獲取物件型別、欄位型別與值、呼叫struct實體方法、更新實體值等;
??Go關于反射相關的物件、函式都在reflect包中最主要的兩個為:Type與Value;
??Go提供了下面兩個函式,這兩個是Go反射的核心;
??reflect.TypeOf 回傳目標物件的型別
??reflect.ValueOf 回傳值目標物件的值
t:=1
fmt.Println(reflect.TypeOf(t), reflect.ValueOf(t))
輸出:int 1
通過反射操作Struct
type Demo struct {
Id int
Name string
}
func (d *Demo) Back() {
fmt.Println("呼叫方法 Back")
}
func (d *Demo) Add(a, b int) int {
return a + b
}
獲取結構體中每個成員變數的名稱與值:
d := &Demo{Id: 2, Name: "test"}
getValue(d)
輸出: Id : 2
Name : test
func getValue(v interface{}) {
t := reflect.TypeOf(v)
o := reflect.ValueOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem() //獲取型別指標中的型別
}
if o.Kind() == reflect.Ptr {
o = o.Elem() //獲取值地址中的值
}
num := t.NumField() //獲取欄位個數
for i := 0; i < num; i++ {
f := o.Field(i) //獲取欄位的值
fieldName := t.Field(i).Name //獲取欄位名稱
switch f.Kind() {
case reflect.Int:
fmt.Println(fieldName, ": ", f.Int())
case reflect.String:
fmt.Println(fieldName, ": ", f.String())
default:
fmt.Println("型別不不支持")
}
}
}
??對于參考型別使用reflect.TypeOf回傳的是該型別的指標,reflect.ValueOf回傳的是該型別的值地址;所以對于參考型別都要的相關操作都要呼叫Elem()函式獲取真實的型別與值;
??呼叫Type或Value物件的NumField函式獲取結構體的欄位個數
??呼叫Value物件的Field(i) 可獲取欄位的值;
??呼叫Value物件的Kind()函式可獲取欄位的型別;
??該Value對應于哪種型別呼叫對應的函式即可獲取得到相應的值,如型別不一致將拋出:panic: reflect: call of reflect.Value.Xxx on int Value;
修改結構體中每個成員變數的值:
d := new(Demo)
setValue(d)
fmt.Println(d)
輸出:&{88 Test}
func setValue(v interface{}) {
t := reflect.TypeOf(v)
o := reflect.ValueOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if o.Kind() == reflect.Ptr {
o = o.Elem()
}
num := t.NumField()
for i := 0; i < num; i++ {
f := o.Field(i)
switch f.Kind() {
case reflect.Int:
f.SetInt(88) //往該欄位設值
case reflect.String:
f.SetString("Test") /往該欄位設值
default:
fmt.Println("型別不支持")
}
}
}
??修改欄位值與獲取值一樣,型別一定要一致,如不一致將拋例外,如int型別卻呼叫SetString設值:panic: reflect: call of reflect.Value.SetString on int Value;
呼叫結構體的無參方法:
d := new(Demo)
callMethod(d)
輸出:呼叫方法 Back
func callMethod(v interface{}) {
o := reflect.ValueOf(v)
o.MethodByName("Back").Call(nil)
}
??呼叫MethodByName根據名稱獲取方法,Call呼叫該方法;
呼叫結構體的有參方法:
d := new(Demo)
callMethodParam (d)
輸出:3
func callMethodParam(p interface{}) {
o := reflect.ValueOf(p)
args:=[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
v:= o.MethodByName("Add").Call(args)
fmt.Println(v[0])
}
??比較常用的方法還有:
??使用名字獲取結構體的成員
Refletct.ValueOf(*e).FieldByName(“Name”)
??獲取結構體成員的json標記資訊
reflect.TypeOf(s) . Field(0).Tag.Get(“key”)
??Golang的反射也遵循Go語言規則,反射無法修改結構體中的私有物件,無法呼叫私有私有方法,可訪問私有成員,修改私有成員將會拋出reflect.flag.mustBeAssignable例外;

文章首發地址:Solinx
https://mp.weixin.qq.com/s/W0UVbFxMMeXA5HuNNZlK-A
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/9998.html
標籤:Go
