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() }