go語言中reflect反射機制。詳細原文:地址golang
package main import ( "fmt" "reflect" ) func main() { var x int = 1 fmt.Println("type: ", reflect.TypeOf(x)) }
type: int
TypeOf
函數的定義以下,參數爲接口類型,返回值爲類型函數
func TypeOf(i interface {}) Type
ValueOf
函數的定義以下,參數爲接口類型,返回值爲Value
code
var x int = 1 fmt.Println("value: ", reflect.ValueOf(x))
value: <int Value>
能夠經過Kind
函數來檢查類型,對象
fmt.Println("Kind: ", reflect.ValueOf(x).Kind()) fmt.Println("Kind is Int? ", reflect.ValueOf(x).Kind() == reflect.int)
Kind: int Kind is Int? true
經過Interface
函數能夠實現反射對象到接口值的轉換,blog
func (v Value) Interface() interface {}
// Interface 以 interface{} 返回 v 的值 y := v.Interface().(float64) fmt.Println(y)
修改反射對象的前提條件是其值必須是可設置的接口
var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.3) // Error: panic
爲了不這個問題,須要使用CanSet
函數來檢查該值的設置性,ci
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("settability of v: ", v.CanSet())
settability of v: false
那麼如何才能設置該值呢?
這裏須要考慮一個常見的問題,參數傳遞
,傳值仍是傳引用或地址?
在上面的例子中,咱們使用的是reflect.ValueOf(x)
,這是一個值傳遞,傳遞的是x的值的一個副本,不是x自己,所以更新副本中的值是不容許的。若是使用reflect.ValueOf(&x)
來替換剛纔的值傳遞,就能夠實現值的修改。get
var x float64 = 3.4 p := reflect.ValueOf(&x) // 獲取x的地址 fmt.Println("settability of p: ", p.CanSet()) v := p.Elem() fmt.Println("settability of v: ", v.CanSet()) v.SetFloat(7.1) fmt.Println(v.Interface()) fmt.Println(x)
settability of p: false settability of v: true 7.1 7.1
首先介紹如何遍歷結構體字段內容,
假設結構體以下,string
type T struct { A int B string } t := T{12, "skidoo"}
從而,經過反射來遍歷全部的字段內容it
s := reflect.ValueOf(&t).Elem() typeOfT := s.Type() for i := 0; i < s.NumField(); i++ { f := s.Field(i) fmt.Printf("%d %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) }
0 A int = 23 1 B string = skidoo
接下來,如何獲取結構體的標籤內容?
func main() { type S struct { F string `species:"gopher" color:"blue"` } s := S{} st := reflect.TypeOf(s) field := st.Field(0) fmt.Println(field.Tag.Get("color"), field.Tag.Get("species")) }
通常狀況下,爲了存儲多個函數值,通常採用map
來存儲。其中key爲函數名稱,而value爲相應的處理函數。
在這裏須要定義好函數類型,可是函數的參數以及返回類型就須要是統一的,以下
package main import "fmt" func say(text string) { fmt.Println(text) } func main() { var funcMap = make(map[string]func(string)) funcMap["say"] = say funcMap["say"]("hello") }
若是但願map
能夠存儲任意類型的函數(參數不一樣,返回值不一樣),那麼就須要用interface{}而不是func(param...)來定義value。
package main import "fmt" func say(text string) { fmt.Println(text) } func main() { var funcMap = make(map[string]interface{}) funcMap["say"] = say funcMap["say"]("hello") }
cannot call non-function funcMap["say"] (type interface {})
直接調用會報錯,提示不能調用interface{}類型的函數。
這時,須要利用reflect
把函數從interface轉換到函數來使用,
package main import ( "fmt" "reflect" ) func say(text string) { fmt.Println(text) } func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value) { f := reflect.ValueOf(m[name]) in := make([]reflect.Value, len(params)) for k, param := range params { in[k] = reflect.ValueOf(param) } result = f.Call(in) return } func main() { var funcMap = make(map[string]interface{}) funcMap["say"] = say Call(funcMap, "say", "hello")