s1 := reflect.TypeOf((int8)(0)).String() // int8
等同於下面這個:html
var i8 int8 = 0 reflect.TypeOf(i8).String() // int8
reflect.TypeOf((*int8)(nil)).String() // *int8
等同於:golang
var i8 *int8 = nil reflect.TypeOf(i8).String() // *int8
reflect.TypeOf((*int8)(nil)).Elem().String() // int8
st := (*struct { a int })(nil) reflect.TypeOf(st).String() // *struct { a int } reflect.TypeOf(st).Elem().String() // struct { a int }
reflect.TypeOf(st).Elem().Field(0).Type.String() // int f, found := reflect.TypeOf(st).Elem().FieldByName("a") if !found { fmt.Println("no field 'a'.") } else { fmt.Println(f.Type.String()) // int }
func main() { var i1 interface{} i1 = &T{"t1"} var i2 interface{} i2 = T{"t2"} v1 := reflect.ValueOf(i1) v2 := reflect.ValueOf(i2) // 字段 // fmt.Println(v1.FieldByName("A")) // err: call of reflect.Value.FieldByName on ptr Value fmt.Println(v2.FieldByName("A")) // 方法 fmt.Println(v1.MethodByName("Fun1")) fmt.Println(v1.MethodByName("Fun2")) fmt.Println(v2.MethodByName("Fun1")) fmt.Println(v2.MethodByName("Fun2")) // <invalid Value> if m := v2.MethodByName("Fun2"); m.IsValid() { fmt.Println("v2.Fun2() is valid.") } else { fmt.Println("v2.Fun2() is invalid") // this one } } type T struct { A string } func (t T) Fun1() { } func (t *T) Fun2() { }
指針不能獲取到字段值。數組
非指針不能獲取到接受者是指針的方法,但反之卻能夠。app
獲取到方法後判斷一下是否是可用(
IsValid()
)函數
reflect.TypeOf([32]int{}).String() // [32]int
reflect.TypeOf([32]int{}).Elem().String() // int
maptype := reflect.TypeOf((map[string]*int32)(nil)) maptype.String() // map[string]*int32 maptype.Key().String() // string maptype.Elem().String() // *int32
chantype := reflect.TypeOf((chan<- string)(nil)) chantype.String() // chan<- string chantype.Elem().String() // string
var inter struct { E interface{} } inter.E = 123.456 innerPtrValue := reflect.ValueOf(&inter) eField := innerPtrValue.Elem().Field(0) eField.Type() // interface {} reflect.ValueOf(eField.Interface()).Type() // float64
或者測試
eField.Elem().Type()
var i interface{} i = "hello" t := reflect.ValueOf(i).Type() fmt.Println(t) // string
但若是傳給i的是個指針的話:this
var i interface{} s := "hello" i = &s t := reflect.ValueOf(i).Type() fmt.Println(t) // *string
若是使用reflect.ValueOf(i).Elem().Type()
能夠得到,可是這個對於不是指針的話就會報錯,由於Elem()不能用於string指針
可使用reflect.Indirect():code
var i interface{} s := "hello" i = &s // i = s也是輸出string v := reflect.ValueOf(i) t := reflect.Indirect(v).Type() fmt.Println(t) // string
下面是Indirect()的實現:htm
func Indirect(v Value) Value { if v.Kind() != Ptr { return v } return v.Elem() }
能夠參考一下接口爲nil時類型和值都必須是nil的介紹。
reflect.TypeOf((int)(0)).Kind() == reflect.Int reflect.TypeOf((*int)(nil)).Kind() == reflect.Ptr reflect.TypeOf((map[string]string)(nil)).Kind() == reflect.Map
反射對象的 Kind 描述了底層類型,而不是靜態類型。若是一個反射對象包含了用戶定義的整數類型的值,就像:
type MyInt int var x MyInt = 7 v := reflect.ValueOf(x)
v 的 Kind 仍然是 reflect.Int,儘管 x 的靜態類型是 MyInt,而不是 int。換句話說,Kind 沒法從 MyInt 中區分 int,而 Type 能夠。
func getFuncName(f interface{}) string { longName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() parts := strings.Split(longName, ".") if len(parts) > 0 { return parts[len(parts)-1] } return "?" }
SetXXX系列函數要求CanSet()返回true。
先判斷類型在設置值
i := 123 iptr := &i v := reflect.ValueOf(iptr).Elem() if v.Kind() == reflect.Int { v.SetInt(321) } fmt.Println(i) // 321
不判斷類型直接設置值
var i int = 123 iptr := &i v := reflect.ValueOf(iptr).Elem() v.Set(reflect.ValueOf(int(321))) fmt.Println(i) // 321
var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.1) // Error: will panic.
這裏報錯是由於 v 沒法設置值給 x。
Value的 CanSet 方法提供了值的設置性;在這個例子中,
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("settability of v:" , v.CanSet()) // false
建立 v 時傳遞的是 x 的副本給 reflect.ValueOf(),而不是 x 自己。
var x float64 = 3.4 p := reflect.ValueOf(&x) // 注意:獲取 X 的地址。 fmt.Println("type of p:", p.Type()) // type of p: *float64 fmt.Println("settability of p:" , p.CanSet()) // settability of p: false
反射對象 p 並非可設置的,並且咱們也不但願設置 p,其實是 *p。爲了得到 p 指向的內容,調用值上的 Elem 方法,從指針間接指向,而後保存反射值的結果叫作 v:
v := p.Elem() fmt.Println("settability of v:" , v.CanSet()) // true v.setFloat(7.1)
經過 reflect.Indirect() 方法來取指針指向的具體值更好。
arrval := reflect.ValueOf(&[...]int{1, 2, 3}).Elem() arrval.Index(1).SetInt(5) out := "[" for i := 0; i < arrval.Len(); i++ { out += strconv.Itoa(int(arrval.Index(i).Int())) + "," } out += "]" fmt.Println(out) // [1,5,3,]
ValueOf()的參數需是數組指針,下面這個是錯誤的
reflect.ValueOf([...]int{1, 2, 3})
對於切片來講則不須要這麼麻煩(由於經過切片獲取到的數組是指針)
arrval := reflect.ValueOf([]int{1, 2, 3}) arrval.Index(1).SetInt(5)
var ip *int32 var i int32 = 123 vip := reflect.ValueOf(&ip) // **int32 vi := reflect.ValueOf(&i).Elem() // 非得這樣嗎?(直接傳遞i給ValueOf會複製i) vip.Elem().Set(vi.Addr()) // *int32.Set(*int32) fmt.Println(*ip) // 123
將指針設置爲零值
var i int32 = 123 ip := &i vp := reflect.ValueOf(&ip).Elem() vp.Set(reflect.Zero(vp.Type())) fmt.Println(ip) // <nil>
設置map爲空值
m := make(map[string]int) m["a"], m["b"] = 1, 2 mp := reflect.ValueOf(&m).Elem() mp.Set(reflect.Zero(mp.Type())) fmt.Println(m) // map[] fmt.Println(m == nil) // true
從匿名結構體經過Interface()還原到實際類型
b := struct{ a, b, c, d int64 }{1, 2, 3, 4} v := reflect.ValueOf(b) b1 := v.Interface().(struct { a, b, c, d int64 }) fmt.Println(b1) // {1 2 3 4}
interface()不可用於結構體中未導出字段
var st struct { PublicField string privateField string } vSt := reflect.ValueOf(&st).Elem() vSt.Field(0).IsValid() // true vSt.Field(1).IsValid() // true defer func() { if err := recover(); err != nil { fmt.Println("has error :", err) } }() //vSt.Field(0).Interface() // 沒有panic vSt.Field(1).Interface() // panic
var st struct { f1 string `tag1:"cont1" tag2:cont2 tag3:3` } var f1Tag = reflect.TypeOf(st).Field(0).Tag f1Tag.Get("tag1") // cont1 f1Tag.Get("tag2") // 空字符串 f1Tag.Get("tag3") // 空字符串
a := []int{1, 2, 3, 4, 5, 6} b := []int{11, 12, 13, 14, 15} aa := reflect.ValueOf(&a).Elem() bb := reflect.ValueOf(&b).Elem() aa.SetLen(4) // 限制長度只到第4個 reflect.Copy(bb, aa) // 賦值aa的前4個到b裏 aa.SetLen(6) // 回覆長度 fmt.Println(a) // [1 2 3 4 5 6] fmt.Println(b) // [1 2 3 4 15]
a := [...]int{1, 2, 3} b := [...]int{11, 12, 13, 14, 15} aa := reflect.ValueOf(&a).Elem() bb := reflect.ValueOf(&b).Elem() reflect.Copy(bb, aa) fmt.Println(b) // [1 2 3 14 15]
func main() { t := &T{"a", "b"} val := reflect.Indirect(reflect.ValueOf(t)) typ := val.Type() for i := 0; i < val.NumField(); i++ { f := typ.Field(i) fmt.Println(f.Name) } } type T struct { PublicField string privateField string }
輸出:
PublicField privateField
t := &T{"a", "b"} val := reflect.Indirect(reflect.ValueOf(t)) typ := val.Type() typepath := typ.PkgPath() fmt.Println("type pkgPath: ", typepath) // type pkgPath: main for i := 0; i < val.NumField(); i++ { f := typ.Field(i) p := f.PkgPath fmt.Println(f.Name, " => ", p) } // PublicField => // privateField => main
文檔: https://golang.org/pkg/reflect/#Select
和select結構功能同樣,但這個能夠直接指定數組。
測試代碼:
import ( "fmt" "reflect" ) func main() { selectCase := make([]reflect.SelectCase, 3) for i := 0; i < 3; i++ { c := make(chan string) selectCase[i].Dir = reflect.SelectRecv selectCase[i].Chan = reflect.ValueOf(c) go func(i int, c chan string) { for j := 0; j < 5; j++ { c <- fmt.Sprintf("groutine#%d send %d", i, j) } fmt.Printf("groutine#%d closed\n", i) close(c) }(i, c) } done := 0 finished := 0 for finished < len(selectCase) { chosen, recv, recvOk := reflect.Select(selectCase) if recvOk { done++ fmt.Printf("receive #%d, value=%s\n", chosen, recv.String()) } else { fmt.Printf("#%d closed\n", chosen) selectCase = append(selectCase[:chosen], selectCase[chosen+1:]...) } } fmt.Println("done:", done) // 15 }
// From html/template/content.go // Copyright 2011 The Go Authors. All rights reserved. // indirect returns the value, after dereferencing as many times // as necessary to reach the base type (or nil). func indirect(a interface{}) interface{} { if a == nil { return nil } if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { // Avoid creating a reflect.Value if it's not a pointer. return a } v := reflect.ValueOf(a) for v.Kind() == reflect.Ptr && !v.IsNil() { v = v.Elem() } return v.Interface() }