Golang 标准库 reflect

it2023-01-25  57

Golang 标准库 reflect

1. 概念1.1 什么是反射1.2 反射的三大定律1.2.1 第一定律1.2.2 第二定律1.2.3 第三定律 2. 类型(Type)2.1 Type和Kind的区别2.2 方法 `Type.Elem()`2.3 辅助判断方法2.4 结构体 3. 值(Value)3.1 通过反射,修改内容3.2 通道对象设置3.3 空接口判断3.4 结构体3.5 结构体匿名字段或嵌入字段 4. 总结4.1 调用方法4.2 调用变参方法4.3 构建类型 (MakeXXX())4.4. 复合体反射

1. 概念

1.1 什么是反射

反射:在运行时,动态获取对象的类型和内存结构

反射操作所需要的全部信息都源自接口变量,接口变量除了存储自身类型外,还会保存实际对象的类型数据

将任何传入的对象转换为接口类型:

func TypeOf(o interface{}) Type func ValueOf(o interface{}) Value

1.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.)

1.2.1 第一定律

“接口变量” => “反射对象”

reflect.TypeOf(i): 获取接口值的类型 (*reflect.rtype)reflect.ValueOf(i): 获取接口值的值 (reflect.Value)

1.2.2 第二定律

“反射对象” => “接口变量”

注意:只有Value才能逆向转换,Type则不行

func (v Value) Interface() (i interface{}) { return valueInterface(v, true) }

第一和第二定律综合:

1.2.3 第三定律

要修改反射对象,其值必须可写的。

非指针变量创建的反射对象,不可写CanSet()返回true,为可写对象不可写对象,无法进行写操作可写对象,使用Elem()函数返回指针指向的数据 func main() { s := "abc" v1 := reflect.ValueOf(s) fmt.Println(v1.CanSet()) // false v2 := reflect.ValueOf(&s) fmt.Println(v2.CanSet()) // false v3 := v2.Elem() // 只有引用类型,才有Elem()方法 fmt.Println(v3.CanSet()) // true }

可写对象的相关方法:

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)

2. 类型(Type)

func TypeOf(i interface{}) Type { eface := *(*emptyInterface)(unsafe.Pointer(&i)) return toType(eface.typ) }

reflect.Type: 以接口的形式存在

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 }

2.1 Type和Kind的区别

Type: 真实类型(静态类型) t.Name()Kind: 基础类型(底层类型) t.Kind() func main() { type X int var a X = 10 t1 := reflect.TypeOf(a) fmt.Println(t1, t1.Name(), t1.Kind()) // main.X X int t2 := reflect.TypeOf(&a) fmt.Println(t2, t2.Name(), t2.Kind()) // *main.X "" ptr t3 := t2.Elem() fmt.Println(t3, t3.Name(), t3.Kind()) // main.X X int // 基类型 和 指针类型 fmt.Println(t1 == t3) // true }

2.2 方法 Type.Elem()

返回引用类型 (指针、数组、切片、字典值 或 通道) 的基类型

func main() { a := [...]byte{1, 2, 3} s := []int{1, 2, 3} m := make(map[int]string) c := make(chan bool) ta := reflect.TypeOf(a) ts := reflect.TypeOf(s) tm := reflect.TypeOf(m) tc := reflect.TypeOf(c) fmt.Println(ta, ta.Elem()) // [3]uint8 uint8 fmt.Println(ts, ts.Elem()) // []int int fmt.Println(tm, tm.Elem()) // map[int]string string fmt.Println(tc, tc.Elem()) // chan bool bool }

2.3 辅助判断方法

Implements(), ConvertibleTo(), AssignableTo()

func main() { type X int var a X t := reflect.TypeOf(a) fmt.Println(t) // main.X ts := reflect.TypeOf((*fmt.Stringer)(nil)).Elem() fmt.Println(ts) // fmt.Stringer ti := reflect.TypeOf(10) fmt.Println(ti) // int fmt.Println(t.Implements(ts)) // false //fmt.Println(t.Implements(ti)) // panic: reflect: non-interface type passed to Type.Implements fmt.Println(t.ConvertibleTo(ts)) // false fmt.Println(t.ConvertibleTo(ti)) // true fmt.Println(t.AssignableTo(ts)) // false fmt.Println(t.AssignableTo(ti)) // false }

2.4 结构体

获取结构体内容: Field(), FieldByIndex(), FieldByName(), FieldByNameFunc()

type StructField struct { Name string PkgPath string Type Type // field type Tag StructTag // field tag string Offset uintptr // offset within struct, in bytes Index []int // index sequence for Type.FieldByIndex Anonymous bool // is an embedded field } func main() { user := struct { Name string `json:"name"` Age byte `json:"age"` }{"daniel", 21} t := reflect.TypeOf(user) for i := 0; i < t.NumField(); i++ { tf := t.Field(i) fmt.Println(tf.Name, tf.Type, tf.Tag) // Name string json:"name" } if tf, ok := t.FieldByName("Age"); ok { fmt.Println(tf.Type, tf.Tag.Get("json")) // uint8 age } }

3. 值(Value)

reflect.Value: 以结构体形式存在

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)

3.1 通过反射,修改内容

接口变量会复制对象,是unaddressable的;要想修改目标对象,必须使用指针;传入的值必选是pointer-interface

func main() { x := 10 v1 := reflect.ValueOf(x) fmt.Println(v1.CanAddr(), v1.CanSet()) // false, false fmt.Println(v1.Kind() == reflect.Ptr) // false v2 := reflect.ValueOf(&x) fmt.Println(v2.CanAddr(), v2.CanSet()) // false, false fmt.Println(v2.Kind() == reflect.Ptr) // true fmt.Println(v2.Elem().CanAddr(), v2.Elem().CanSet()) // true, true v2.Elem().SetInt(5) fmt.Println(x) // 5 }

3.2 通道对象设置

func main() { ch := make(chan int, 4) v := reflect.ValueOf(ch) if v.TrySend(reflect.ValueOf(10)) { fmt.Println(v.TryRecv()) // 10 true } }

3.3 空接口判断

func main() { var a interface{} = nil var b interface{} = (*interface{})(nil) va := reflect.ValueOf(a) vb := reflect.ValueOf(b) fmt.Println(a == nil, b == nil) // true false fmt.Println(va.IsValid(), vb.IsValid()) // false true if vb.IsValid() { fmt.Println(vb.IsNil(), vb.IsZero()) // true true } }

3.4 结构体

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 Info(o interface{}) { t := reflect.TypeOf(o) v := reflect.ValueOf(o) if v.Kind() == reflect.Ptr { t = t.Elem() v = v.Elem() } // Field() fmt.Println("fields:") for i := 0; i < v.NumField(); i++ { tf := t.Field(i) vf := v.Field(i) fmt.Printf("%6s: %v %v\n", tf.Name, tf.Type, vf.Interface()) } // FieldByIndex() tf1 := t.FieldByIndex([]int{1}) vf1 := v.FieldByIndex([]int{1}) fmt.Println(tf1.Name, vf1.String()) // FieldByName() tf2, ok := t.FieldByName("Age") if ok { vf2 := v.FieldByName("Age") fmt.Println(tf2.Name, vf2.Uint()) } // Type.Method(), 注意:只对接收者为User的方法有效,*User的方法不行 fmt.Println("methods:") for i := 0; i < t.NumMethod(); i++ { m := t.Method(i) fmt.Printf("%6s: %v\n", m.Name, m.Type) } // Value.MethodByName() m := v.MethodByName("Say") args := []reflect.Value{reflect.ValueOf("Hi")} m.Call(args) } func Set(o interface{}) { v := reflect.ValueOf(o) if v.Kind() != reflect.Ptr { fmt.Println("Not a pointer interface") return } v = v.Elem() if !v.CanSet() { fmt.Println("Can not be set") return } vf := v.FieldByName("Age") if !vf.IsValid() { fmt.Println("Field not exist") return } if vf.Kind() == reflect.Uint8 { vf.SetUint(25) } fmt.Println(o) } func main() { u := User{1, "Iren", 20} Info(&u) Set(&u) }

3.5 结构体匿名字段或嵌入字段

反射匿名或嵌入字段:匿名字段当独立字段处理

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)) // {Name:"User", ..., Anonymous:true} fmt.Printf("%#v\n", t.Field(1)) // {Name:"Title", ..., Anonymous:false} fmt.Printf("%#v\n", t.FieldByIndex([]int{0})) // Same as t.Field(0),{Name:"User", ..., Anonymous:true} fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1})) // {Name:"Name", ..., Anonymous:false} field, ok := t.FieldByName("Title") if ok { fmt.Printf("%#v\n", field) // {Name:"Title", ..., Anonymous:false} } field, ok = t.FieldByName("Id") if ok { fmt.Printf("%#v\n", field) // {Name:"Id", ..., Anonymous:false} } }

4. 总结

4.1 调用方法

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 调用变参方法

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(9), } result := m.Call(args) fmt.Println(result) // [x = 9] args = []reflect.Value{ reflect.ValueOf("%d + %d = %d"), reflect.ValueOf([]interface{}{1, 2, 1 + 2}), } result = m.CallSlice(args) fmt.Println(result) // [1 + 2 = 3] }

4.3 构建类型 (MakeXXX())

反射库提供了内置函数 make() 和 new() 的对应操作,例如 MakeFunc()。可用它实现通用模板,适应不同数据类型。

func main() { var intAdd func(x, y int) int var strAdd func(x, y string) string makeAdd(&intAdd) makeAdd(&strAdd) fmt.Println(intAdd(8, 9)) fmt.Println(strAdd("Hi", "sara")) } 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 }

4.4. 复合体反射

func walk(x interface{}, fn func(string)) { val := getValue(x) walkValue := func(value reflect.Value) { walk(value.Interface(), fn) } switch val.Kind() { case reflect.String: fn(val.String()) case reflect.Struct: for i := 0; i < val.NumField(); i++ { walkValue(val.Field(i)) } case reflect.Slice, reflect.Array: for i := 0; i < val.Len(); i++ { walkValue(val.Index(i)) } case reflect.Map: for _, key := range val.MapKeys() { walkValue(val.MapIndex(key)) } } } func getValue(x interface{}) reflect.Value { val := reflect.ValueOf(x) if val.Kind() == reflect.Ptr { val = val.Elem() } return val } func TestWalk(t *testing.T) { cases := []struct { Name string Input interface{} Expected []string }{ { "test struct", struct { Name string }{"Daniel"}, []string{"Daniel"}, }, { "test map", map[int]string{1: "a"}, []string{"a"}, }, } for _, test := range cases { t.Run(test.Name, func(t *testing.T) { var got []string walk(test.Input, func(s string) { got = append(got, s) }) if !reflect.DeepEqual(got, test.Expected) { t.Fatalf("expected: %v, but got %v\n", test.Expected, got) } }) } }
最新回复(0)