1. 反射 反射:在运行时,动态获取对象的类型信息和内存结构
反射操作所需要的全部信息都源自接口变量,接口变量除了存储自身类型外,还会保存实际对象的类型数据
将任何传入的对象转换为接口类型:
1 2 func TypeOf (o interface {}) Type func ValueOf (o interface {}) Value
2. 类型(Type) reflect.TypeOf()
返回对象类型
1 2 3 4 func TypeOf (i interface {}) Type { eface := *(*emptyInterface)(unsafe.Pointer(&i)) return toType(eface.typ) }
2.1 Type和Kind的区别
Type: 真实类型(静态类型) t.Name()
Kind: 基础类型(底层类型) t.Kind()
1 2 3 4 5 6 7 8 func main () { type X int var a X = 100 t := reflect.TypeOf(a) fmt.Println(t, t.Name(), t.Kind()) }
2.2 基类型和指针类型 1 2 3 4 5 6 7 8 9 10 func main () { x := 20 tx := reflect.TypeOf(x) tp := reflect.TypeOf(&x) fmt.Println(tx, tx.Name(), tx.Kind()) fmt.Println(tp, tp.Name(), tp.Kind()) fmt.Println(tx == tp.Elem()) }
2.3 方法Type.Elem()
返回引用类型 (指针、数组、切片、字典(值)或 通道) 的基类型
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () {a := [...]byte {1 , 2 , 3 } s := make ([]string , 5 ) m := make (map [int ]string ) ta := reflect.TypeOf(a) ts := reflect.TypeOf(s) tm := reflect.TypeOf(m) fmt.Println(ta, ta.Elem()) fmt.Println(ts, ts.Elem()) fmt.Println(tm, tm.Elem()) }
2.4 辅助判断方法 Implements(), ConvertibleTo(), AssignableTo()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func main () { type X int var a X t := reflect.TypeOf(a) fmt.Println(t) ts := reflect.TypeOf((*fmt.Stringer)(nil )).Elem() fmt.Println(ts) ti := reflect.TypeOf(10 ) fmt.Println(ti) fmt.Println(t.Implements(ts)) fmt.Println(t.ConvertibleTo(ts)) fmt.Println(t.ConvertibleTo(ti)) fmt.Println(t.AssignableTo(ts)) fmt.Println(t.AssignableTo(ti)) }
2.5 结构体 反射类型 Field(), FieldByIndex(), FieldByName(), FieldByNameFunc() 获取 StructField结构体中的内容
1 2 3 4 5 6 7 8 9 10 type StructField struct { Name string PkgPath string Type Type Tag StructTag Offset uintptr Index []int Anonymous bool }
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { user := User{"Jack" , 12 } t := reflect.TypeOf(user) for i := 0 ; i < t.NumField(); i++ { tf := t.Field(i) fmt.Printf("%s: %s %v\n" , tf.Name, tf.Type, tf.Tag) } if tf, ok := t.FieldByName("Age" ); ok { fmt.Printf("%s: %s\n" , tf.Name, tf.Tag.Get("json" )) } }
3. 值(Value) 接口变量会复制对象,是unaddressable的。要想修改目标对象,必须使用指针
1 2 3 4 5 6 7 8 9 10 func main () { a := 5 va := reflect.ValueOf(a) vp := reflect.ValueOf(&a).Elem() fmt.Println(va, vp) fmt.Println(va.CanAddr(), va.CanSet()) fmt.Println(vp.CanAddr(), vp.CanSet()) }
3.1 结构体反射 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 type User struct { Id int Name string Age byte } func (u User) Hello () { fmt.Println("Hello" , u.Name) } func (u User) Say (msg string ) { fmt.Println(u.Name, "say" , msg) } func main () { u := User{1 , "Jack" , 23 } Info(u) Set(&u) fmt.Println(u) } func Info (o interface {}) { t := reflect.TypeOf(o) fmt.Println("Type:" , t) if k := t.Kind(); k != reflect.Struct { fmt.Println("A Pointer Interface" ) return } v := reflect.ValueOf(o) fmt.Println("Fields:" ) for i := 0 ; i < v.NumField(); i++ { field := t.Field(i) value := v.Field(i).Interface() fmt.Printf("%6s: %v = %v\n" , field.Name, field.Type, value) } f1 := v.FieldByIndex([]int {1 }) fmt.Println(f1.Interface()) f2 := v.FieldByName("Age" ) fmt.Println(f2.Interface()) fmt.Println("Methods:" ) for i := 0 ; i < v.NumMethod(); i++ { m := t.Method(i) fmt.Printf("%6s: %v\n" , m.Name, m.Type) } m1 := v.MethodByName("Say" ) args := []reflect.Value{reflect.ValueOf("Hi" )} m1.Call(args) } func Set (o interface {}) { v := reflect.ValueOf(o) if v.Kind() != reflect.Ptr { fmt.Println("Not a pointer interface" ) return } if !v.Elem().CanSet() { fmt.Println("Can not be set" ) return } v = v.Elem() f := v.FieldByName("Age" ) if !f.IsValid() { fmt.Println("Can not find this field" ) return } if f.Kind() == reflect.Uint8 { f.SetUint(25 ) } }
3.2 处理结构体匿名字段或嵌入字段 反射匿名或嵌入字段:匿名字段当独立字段处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 type User struct { Id int Name string Age byte } type Manager struct { User Title string } func main () { m := Manager{User: User{1 , "Jack" , 21 }, Title: "CEO" } t := reflect.TypeOf(m) fmt.Printf("%#v\n" , t.Field(0 )) fmt.Printf("%#v\n" , t.Field(1 )) fmt.Printf("%#v\n" , t.FieldByIndex([]int {0 })) fmt.Printf("%#v\n" , t.FieldByIndex([]int {0 , 1 })) field, ok := t.FieldByName("Title" ) if ok { fmt.Printf("%#v\n" , field) } field, ok = t.FieldByName("Id" ) if ok { fmt.Printf("%#v\n" , field) } }
3.3 通过反射,修改内容 传入的值必选是pointer-interface
1 2 3 4 5 6 7 8 func main () { x := 10 v := reflect.ValueOf(&x) fmt.Printf("%#v\n" , v) v.Elem().SetInt(99 ) fmt.Println(x) }
3.4 通道对象设置 1 2 3 4 5 6 7 8 func main () { ch := make (chan int , 4 ) v := reflect.ValueOf(ch) if v.TrySend(reflect.ValueOf(100 )) { fmt.Println(v.TryRecv()) } }
3.5 空接口判断 1 2 3 4 5 6 7 func main () { var a interface {} = nil var b interface {} = (*int )(nil ) fmt.Println(a == nil ) fmt.Println(b == nil , reflect.ValueOf(b).IsNil()) }
4. 方法 4.1 调用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type X struct {}func (X) Add (x, y int ) int { return x + y } func main () { var a X v := reflect.ValueOf(a) m := v.MethodByName("Add" ) args := []reflect.Value{ reflect.ValueOf(5 ), reflect.ValueOf(7 ), } result := m.Call(args) for _, val := range result { fmt.Println(val) } }
4.2 调用变参方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type X struct {}func (X) Format (format string , a ...interface {}) string { return fmt.Sprintf(format, a...) } func main () { var a X v := reflect.ValueOf(a) m := v.MethodByName("Format" ) args := []reflect.Value{ reflect.ValueOf("%s = %d" ), reflect.ValueOf("x" ), reflect.ValueOf(10 ), } result := m.Call(args) fmt.Println(result) args = []reflect.Value{ reflect.ValueOf("%d + %d = %d" ), reflect.ValueOf([]interface {}{1 , 2 , 1 + 2 }), } result = m.CallSlice(args) fmt.Println(result) }
5. 构建 反射库提供了内置函数 make() 和 new() 的对应操作,例如 MakeFunc()。可用它实现通用模板,适应不同数据类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 func main () { var intAdd func (x, y int ) int var strAdd func (x, y string ) string makeAdd(&intAdd) makeAdd(&strAdd) fmt.Println(intAdd(20 , 30 )) fmt.Println(strAdd("Hello" , "World" )) } func makeAdd (o interface {}) { fn := reflect.ValueOf(o).Elem() v := reflect.MakeFunc(fn.Type(), add) fn.Set(v) } func add (args []reflect.Value) (results []reflect.Value) { if len (args) == 0 { return nil } var ret reflect.Value switch args[0 ].Kind() { case reflect.Int: sum := 0 for _, n := range args { sum += int (n.Int()) } ret = reflect.ValueOf(sum) case reflect.String: ss := make ([]string , 0 , len (args)) for _, s := range args { ss = append (ss, s.String()) } ret = reflect.ValueOf(strings.Join(ss, " " )) } results = append (results, ret) return }
6. 反射相关方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 reflect.TypeOf(o) reflect.Type.Name() reflect.Type.Kind() reflect.ValueOf(o) reflect.Value.Type() reflect.Value.Kind() reflect.Value.Float() reflect.Value.Int() reflect.Value.String() reflect.Value.Bool() reflect.Value.Interface() ptr.Elem().setInt(99 ) reflect.Value.SetInt() reflect.Value.SetFloat() reflect.Value.SetString() reflect.Value.NumField() reflect.Value.Field(i) reflect.Value.FieldByIndex(i) reflect.Value.FieldByName("field" ) reflect.StructField.Name reflect.StructField.Type reflect.Value.NumMethod() reflect.Value.Method(i) reflect.Value.MethodByName("method" ) reflect.Method.Name reflect.Method.Type reflect.Method.Call(in []Value)
7. 反射的三大定律 7.1 两种类型 Type 和 Value reflect.Type : 以接口的形式存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 type Type interface { Align() int FieldAlign() int Method(int ) Method MethodByName(string ) (Method, bool ) NumMethod() int Name() string PkgPath() string Size() uintptr String() string Kind() Kind Implements(u Type) bool AssignableTo(u Type) bool ConvertibleTo(u Type) bool Comparable() bool Bits() int ChanDir() ChanDir IsVariadic() bool Elem() Type Field(i int ) StructField FieldByIndex(index []int ) StructField FieldByName(name string ) (StructField, bool ) FieldByNameFunc(match func (string ) bool ) (StructField, bool ) In(i int ) Type Key() Type Len() int NumField() int NumIn() int NumOut() int Out(i int ) Type common() *rtype uncommon() *uncommonType }
reflect.Value : 以结构体形式存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 type Value struct { typ *rtype ptr unsafe.Pointer flag } func (v Value) Addr () Value func (v Value) Bool () bool func (v Value) Bytes () []byte func (v Value) Call (in []Value) []Value func (v Value) CallSlice (in []Value) []Value func (v Value) CanAddr () bool func (v Value) CanInterface () bool func (v Value) CanSet () bool func (v Value) Cap () int func (v Value) Close () func (v Value) Complex () complex128 func (v Value) Convert (t Type) Value func (v Value) Elem () Value func (v Value) Field (i int ) Value func (v Value) FieldByIndex (index []int ) Value func (v Value) FieldByName (name string ) Value func (v Value) FieldByNameFunc (match func (string ) bool ) Value func (v Value) Float () float64 func (v Value) Index (i int ) Value func (v Value) Int () int64 func (v Value) Interface () (i interface }) func (v Value) InterfaceData () [2]uintptr func (v Value) IsNil () bool func (v Value) IsValid () bool func (v Value) IsZero () bool func (v Value) Kind () Kind func (v Value) Len () int func (v Value) MapIndex (key Value) Value func (v Value) MapKeys () []Value func (v Value) MapRange () *MapIter func (v Value) Method (i int ) Value func (v Value) MethodByName (name string ) Value func (v Value) NumField () int func (v Value) NumMethod () int func (v Value) OverflowComplex (x complex128 ) bool func (v Value) OverflowFloat (x float64 ) bool func (v Value) OverflowInt (x int64 ) bool func (v Value) OverflowUint (x uint64 ) bool func (v Value) Pointer () uintptr func (v Value) Recv () (x Value, ok bool ) func (v Value) Send (x Value) func (v Value) Set (x Value) func (v Value) SetBool (x bool ) func (v Value) SetBytes (x []byte ) func (v Value) SetCap (n int ) func (v Value) SetComplex (x complex128 ) func (v Value) SetFloat (x float64 ) func (v Value) SetInt (x int64 ) func (v Value) SetLen (n int ) func (v Value) SetMapIndex (key, elem Value) func (v Value) SetPointer (x unsafe.Pointer) func (v Value) SetString (x string ) func (v Value) SetUint (x uint64 ) func (v Value) Slice (i, j int ) Value func (v Value) Slice3 (i, j, k int ) Value func (v Value) String () string func (v Value) TryRecv () (x Value, ok bool ) func (v Value) TrySend (x Value) bool func (v Value) Type () Type func (v Value) Uint () uint64 func (v Value) UnsafeAddr () uintptr func (v Value) assignTo (context string , dst *rtype, target unsafe.Pointer) Value func (v Value) call (op string , in []Value) []Value func (v Value) pointer () unsafe .Pointer func (v Value) recv (nb bool ) (val Value, ok bool ) func (v Value) runes () []rune func (v Value) send (x Value, nb bool ) (selected bool ) func (v Value) setRunes (x []rune )
7.2 反射的三大定律
Reflection goes from interface value to reflection object.
反射可以将接口类型变量 转换为“反射类型对象”
Reflection goes from reflection object to interface value.
反射可以将 “反射类型对象”转换为 接口类型变量
To modify a reflection object, the value must be settable.
如果要修改 “反射类型对象” 其类型必须是 可写的
7.2.1 第一定律 Reflection goes from interface value to reflection object.
reflect.TypeOf(i): 获取接口值的类型 (*reflect.rtype)
reflect.ValueOf(i): 获取接口值的值 (reflect.Value)
7.2.2 第二定律 Reflection goes from reflection object to interface value.
注意:只有Value才能逆向转换,Type则不行
1 2 3 func (v Value) Interface () (i interface {}) { return valueInterface(v, true ) }
7.2.3 第三定律 To modify a reflection object, the value must be settable.
非指针变量创建的反射对象,不可写
CanSet()返回true,为可写对象
不可写对象,无法进行写操作
可写对象,使用Elem()函数返回指针指向的数据
1 2 3 4 5 6 7 8 9 10 11 12 func main () { var name string = "Go编程" v1 := reflect.ValueOf(name) fmt.Println(v1.CanSet()) v2 := reflect.ValueOf(&name) fmt.Println(v2.CanSet()) v3 := v2.Elem() fmt.Println(v3.CanSet()) }
可写对象的相关方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 Set(x Value) SetBool(x bool ) SetBytes(x []byte ) setRunes(x []rune ) SetComplex(x complex128 ) SetFloat(x float64 ) SetInt(x int64 ) SetLen(n int ) SetCap(n int ) SetMapIndex(key Value, elem Value) SetUint(x uint64 ) SetPointer(x unsafe.Pointer) SetString(x string )