reflect 简介 reflect 是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为 。
反射作为一种元编程方式可以减少重复代码,但使用不当,也会使程序变得过于抽象,难以理解,且运行缓慢。
反射机制:在编译时不知道类型的情况下 ,可更新变量 、运行时查看值 、调用方法 以及直接对他们的布局进行操作 。反射机制就是在运行时动态的调用对象的方法和属性。
反射和自省的区别 “反射” 和 “内省”(type introspection)在概念上有区别。内省(或称 “自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测
;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变
程序状态或结构。所以反射的概念范畴要大于内省。
什么时候需要反射 有时候我们需要一个函数可以处理各种类型的值。在不知道类型的情况下,你可能会这么写:
1 2 3 4 5 6 7 8 9 switch value := value.(type ) {case string : case int : case cbsStruct: }
有没发现什么问题?当类型很多,这个函数会写的非常长,而且还可能存在自定的类型,也就是说这个判断日后可能还要一直改,因为无法知道未知值到底属于什么类型。在无法透视一个未知类型的时候,以上代码其实不是很合理,这时候就需要有反射来帮忙你处理,
什么时候需要反射:
不能预先确定参数的类型,可能是因为没有约定好,也可能是传入的参数类型有很多,且不能统一表示。
函数需要根据输入的参数来动态的执行不同的行为。
反射的优缺点 优点:
可以在一定程度上避免硬编码,提供灵活性和通用性。
可以作为一个第一类对象 发现并修改源代码的结构(如代码块、类、方法、协议等)。
缺点:
同样因为反射的概念和语法都比较抽象,滥用反射会使得代码难以被其他人读懂。
无法在编译时检查错误。代码在运行时存在 panic 的风险。
降低了代码运行的效率,反射出变量的类型需要额外的开销。
使用 python 模拟 reflect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class ReflectMethodFactory (object ): def __init__ (self, action ): self.action = action self.reflect = { "get" : self.get, "post" : self.post } def get (self ): print ("get" ) def post (self ): print ("post" ) def main (): r = ReflectMethodFactory("get" ) r.reflect[r.action]() if __name__ == "__main__" : main()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class ReflectMethodFactory (object ): def __init__ (self, action ): self.action = action def get (self ): print ("get" ) def post (self ): print ("post" ) def main (): r = ReflectMethodFactory("get" ) if r.action == "get" : r.get() elif r.action == "post" : r.post()
如果不实用动态映射的话, 来一个方法我就需要加一个if, 我事先定义好一组规则, 然后进行动态映射, 这样是不是方便了很多? 本身是弱类型语言所以可以这么搞, 但是golang中就不能这么搞, 所以才有了reflect。
深入理解反射 变量的 static type 和 concrete type 变量包括(type, value)两部分。type 包括 static type 和 concrete type。
static type 是你在编码是看见的类型 (如 int、string),static type 在创建变量的时候就已经确定。
concrete type 是 runtime 系统看见的类型。
1 2 3 4 5 graph TD; Var-->type; Var-->value; type-->staticType; type-->concreteType;
eg:
1 2 3 4 tty, err := os.OpenFile("/dev/tty" , os.O_RDWR, 0 ) var r io.Readerr = tty
此时,对于变量 r:
value 为 tty
static type 为 io.Reader
concrete type 为 *os.File
对于interface{}
变量,其 static type 就是 interface{}
:
1 2 3 4 tty2, err := os.OpenFile("/dev/tty" , os.O_RDWR, 0 ) var r2 interface {}r2 = tty2
此时,对于变量 r2:
value 为 tty2
static type 为 interface{}
concrete type 为 *os.File
类型断言的本质 类型断言能否成功,取决于变量的 concrete type ,而不是 static type。因此,一个 reader 变量如果它的 concrete type 也实现了 write 方法的话,它也可以被类型断言为 writer。
1 2 var w io.Writerw = r.(io.Writer)
interface{} 类型的两个指针 众所周知,反射是针对 interface 类型的,只有 interface 类型才有反射一说 。而所有的 interface 类型,其 static type 都为 interface{}
。
因此,每个 interface 变量都有一个对应 pair:
pair 中 value 记录了实际变量的值,type 记录了实际变量的类型。
也就是说,一个 interface{} 类型的变量包含了 2 个指针:
一个指针指向实际的值【对应 value】
一个指针指向值的类型【对应 concrete type】
反射的本质 interface 及其 pair 的存在,是 Golang 中实现反射的前提。反射就是用来检测存储在接口变量内部 (值 value;类型 concrete type) pair 对的一种机制 。
TypeOf()、ValueOf() 和 pair 的关系 concrete tpye 决定了该变量支持哪些方法集。value 决定了该变量在内存值的读写。
为了修改 value 和 concrete type,reflect 提供了 TypeOf 和 ValueOf 两个方法:
func ValueOf(i interface{}) Value {...}
:获取 pair 中的 type。
func TypeOf(i interface{}) Type {...}
:获取 pair 中的 value。
反射三大定律
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.
Reflection goes from interface value to reflection object. 从接口值
反射到反射对象
。
从 interface{} 变量可以反射出 reflect 对象,具体来说,通过 reflect.TypeOf 获取了变量的类型,reflect.ValueOf 获取了变量的值。
如果我们知道了一个变量的类型和值,那么就意味着我们知道了这个变量的全部信息。通过 type、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 package reflect_testimport ( "fmt" "reflect" "testing" ) type Coder struct { Name string } func (c *Coder) String () string { return c.Name } func TestCoder (t *testing.T) { coder := &Coder{Name: "obgnail" } typ := reflect.TypeOf(coder) val := reflect.ValueOf(coder) typeOfStringer := reflect.TypeOf((*fmt.Stringer)(nil )).Elem() fmt.Println("kind of coder:" , typ.Kind()) fmt.Println("type of coder:" , typ) fmt.Println("value of coder:" , val) fmt.Println("implements stringer:" , typ.Implements(typeOfStringer)) }
(*fmt.Stringer)(nil)
怎么理解?
答:(*T)(nil)
其实是类型转换。正常的类型转换是T(expr)
,如string(a)
,但是取址符号*
的优先级更高,因此*T(expr)
需要写成(*T)(expr)
所以(*T)(nil)
就很好理解了,这里就是将 nil 转换为*T
类型。所以,var a *fmt.Stringer = (*fmt.Stringer)(nil)
就是返回一个实现了*fmt.Stringer
接口的变量 a。
Reflection goes from reflection object to interface value. 从反射对象
变回 interface{}对象
具体来说,通过 Interface()方法 从反射对象获取interface{} 变量
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 package reflect_testimport ( "fmt" "reflect" "testing" ) type Coder struct { Name string } func (c *Coder) String () string { return c.Name } func TestCoder (t *testing.T) { coder := &Coder{Name: "obgnail" } val := reflect.ValueOf(coder) c, ok := val.Interface().(*Coder) if ok { fmt.Println(c.Name) } else { panic ("type assert to *Coder err" ) } }
可见,第一第二定律是互逆的。通过 ValueOf 方法可以从 Interface 获取反射对象,反射对象调用 Interface() 可以获取 Interface 变量。Interface 变量可以用类型转换再得到原来的变量。
To modify a reflection object, the value must be settable. 要更新一个 reflect.Value,那么它的值必须是可被更新的 。否则将会导致 panic。
辅助判断:
reflect.flag.mustBeAssignable 检查是否可以被设置
reflect.flag.mustBeExported 检查变量是否可以被导出,防止不可导出的的变量泄露
reflect.Value.assignTo 会返回一个新的反射对象,这个返回的反射对象指针会直接覆盖原反射变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func TestReflectionLaw3V1 (t *testing.T) { i := 1 v := reflect.ValueOf(i) v.SetInt(10 ) fmt.Println(i) } func TestReflectionLaw3V2 (t *testing.T) { i := 1 v := reflect.ValueOf(&i) v.Elem().SetInt(10 ) fmt.Println(i) }
Go Reflection Rule
Elem() VS Indirect() 1 2 3 4 5 6 7 8 9 10 func (v Value) Elem () Value func Indirect (v Value) Value { if v.Kind() != Ptr { return v } return v.Elem() }
If a reflect.Value
is a pointer, then v.Elem()
is equivalent to reflect.Indirect(v)
. If it is not a pointer, then they are not equivalent:
If the value is an interface then reflect.Indirect(v)
will return the same value, while v.Elem()
will return the contained dynamic value.
If the value is something else, then v.Elem()
will panic.
The reflect.Indirect
helper is intended for cases where you want to accept either a particular type, or a pointer to that type. One example is the database/sql
conversion routines: by using reflect.Indirect
, it can use the same code paths to handle the various types and pointers to those types.
Kind() 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 Kind uint const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
反射源码分析 reflect 包的核心就在 type.go 和 value.go
deep_equal.go 介绍了 deep equal 的概念和实现
make_func.go 则是在运行时修改函数的栈信息来实现类似多态的特性
swapper.go 则定义了一个通用的 swapper 方法,sort 包中的 swapper 就是用的这个
reflect.go 源码结构
TypeOf interface{} 类型在语言内部是通过 reflect.emptyInterface 结体表示的,其中的 rtype 字段用于表示变量的类型,另一个 word 字段指向内部封装的数据
1 2 3 4 5 type emptyInterface struct { typ *rtype word unsafe.Pointer }
用于获取变量类型的 reflect.TypeOf 函数将传入的变量隐式转换成 reflect.emptyInterface 类型并获取其中存储的类型信息 reflect.rtype
reflect.TypeOf 的实现原理其实并不复杂,它只是将一个 interface{} 变量转换成了内部的 reflect.emptyInterface 表示,然后从中获取相应的类型信息
value.go 源码结构
ValueOf reflect.ValueOf 函数中先调用了 reflect.escapes 保证当前值逃逸到堆上,然后通过 reflect.unpackEface 从接口中获取 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 func ValueOf (i interface {}) Value { if i == nil { return Value{} } escapes(i) return unpackEface(i) } func unpackEface (i interface {}) Value { e := (*emptyInterface)(unsafe.Pointer(&i)) t := e.typ if t == nil { return Value{} } f := flag(t.Kind()) if ifaceIndir(t) { f |= flagIndir } return Value{t, e.word, f} }
Quick start reflect 的基本功能 TypeOf 和 ValueOf 1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport ( "fmt" "reflect" ) func main () { var num float64 = 1.2345 fmt.Println("type: " , reflect.TypeOf(num)) fmt.Println("value: " , reflect.ValueOf(num)) }
reflect.TypeOf: 直接给到了我们想要的 type 类型,如 float64、int、各种 pointer、struct 等等真实的类型
reflect.ValueOf:直接给到了我们想要的具体的值,如 1.2345 这个具体数值,或者类似 &{1 “Allen.Wu” 25} 这样的结构体 struct 的值
也就是说明反射可以将 “接口类型变量” 转换为 “反射类型对象”,反射类型指的是 reflect.Type 和 reflect.Value 这两种
从 relfect.Value 中获取接口 interface 的信息 已知类型后转换为其对应的类型的做法如下,直接通过 Interface 方法然后强制转换,如下:
1 realValue := value.Interface().(已知的类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package mainimport ( "fmt" "reflect" ) func main () { var num float64 = 1.2345 pointer := reflect.ValueOf(&num) value := reflect.ValueOf(num) convertPointer := pointer.Interface().(*float64 ) convertValue := value.Interface().(float64 ) fmt.Println(convertPointer) fmt.Println(convertValue) }
转换的时候,如果转换的类型不完全符合,则直接 panic,类型要求非常严格!
转换的时候,要区分是指针还是指
也就是说反射可以将 “反射类型对象” 再重新转换为 “接口类型变量”
未知原有类型【遍历探测其 Filed】 很多情况下,我们可能并不知道其具体类型,那么这个时候,该如何做呢?需要我们进行遍历探测其 Filed 来得知
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 package mainimport ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (u User) ReflectCallFunc () { fmt.Println("Allen.Wu ReflectCallFunc" ) } func main () { user := User{1 , "Allen.Wu" , 25 } DoFiledAndMethod(user) } func DoFiledAndMethod (input interface {}) { getType := reflect.TypeOf(input) fmt.Println("get Type is :" , getType.Name()) getValue := reflect.ValueOf(input) fmt.Println("get all Fields is:" , getValue) for i := 0 ; i < getType.NumField(); i++ { field := getType.Field(i) value := getValue.Field(i).Interface() fmt.Printf("%s: %v = %v\n" , field.Name, field.Type, value) } for i := 0 ; i < getType.NumMethod(); i++ { m := getType.Method(i) fmt.Printf("%s: %v\n" , m.Name, m.Type) } }
通过运行结果可以得知获取未知类型的 interface 的具体变量及其类型的步骤为:
先获取 interface 的 reflect.Type,然后通过 NumField 进行遍历
再通过 reflect.Type 的 Field 获取其 Field
最后通过 Field 的 Interface () 得到对应的 value
通过运行结果可以得知获取未知类型的 interface 的所属方法(函数)的步骤为:
先获取 interface 的 reflect.Type,然后通过 NumMethod 进行遍历
再分别通过 reflect.Type 的 Method 获取对应的真实的方法(函数)
最后对结果取其 Name 和 Type 得知具体的方法名
也就是说反射可以将 “反射类型对象” 再重新转换为 “接口类型变量”
struct 或者 struct 的嵌套都是一样的判断处理方式
通过 reflect.Value 设置实际变量的值 reflect.Value 是通过 reflect.ValueOf (X) 获得的,只有当 X 是指针的时候,才可以通过 reflec.Value 修改实际变量 X 的值,即:要修改反射类型的对象就一定要保证其值是 “addressable” 的。
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 package mainimport ( "fmt" "reflect" ) func main () { var num float64 = 1.2345 fmt.Println("old value of pointer:" , num) pointer := reflect.ValueOf(&num) newValue := pointer.Elem() fmt.Println("type of pointer:" , newValue.Type()) fmt.Println("settability of pointer:" , newValue.CanSet()) newValue.SetFloat(77 ) fmt.Println("new value of pointer:" , num) pointer = reflect.ValueOf(num) }
需要传入的参数是 * float64 这个指针,然后可以通过 pointer.Elem() 去获取所指向的 Value,注意一定要是指针 。
如果传入的参数不是指针,而是变量,那么
通过 Elem 获取原始值对应的对象则直接 panic
通过 CanSet 方法查询是否可以设置返回 false
newValue.CantSet () 表示是否可以重新设置其值,如果输出的是 true 则可修改,否则不能修改,修改完之后再进行打印发现真的已经修改了。
reflect.Value.Elem () 表示获取原始值对应的反射对象,只有原始对象才能修改,当前反射对象是不能修改的
也就是说如果要修改反射类型对象,其值必须是 “addressable”【对应的要传入的是指针,同时要通过 Elem 方法获取原始值对应的反射对象】
struct 或者 struct 的嵌套都是一样的判断处理方式
通过 reflect.ValueOf 来进行方法的调用 前面我们只说到对类型、变量的几种反射的用法,包括如何获取其值、其类型、如果重新设置新值。但是在工程应用中,另外一个常用并且属于高级的用法,就是通过 reflect 来进行方法【函数】的调用。比如我们要做框架工程的时候,需要可以随意扩展方法,或者说用户可以自定义方法,那么我们通过什么手段来扩展让用户能够自定义呢?关键点在于用户的自定义方法是未可知的,因此我们可以通过 reflect 来搞定
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 package mainimport ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (u User) ReflectCallFuncHasArgs (name string , age int ) { fmt.Println("ReflectCallFuncHasArgs name: " , name, ", age:" , age, "and origal User.Name:" , u.Name) } func (u User) ReflectCallFuncNoArgs () { fmt.Println("ReflectCallFuncNoArgs" ) } func main () { user := User{1 , "Allen.Wu" , 25 } getValue := reflect.ValueOf(user) methodValue := getValue.MethodByName("ReflectCallFuncHasArgs" ) args := []reflect.Value{reflect.ValueOf("wudebao" ), reflect.ValueOf(30 )} methodValue.Call(args) methodValue = getValue.MethodByName("ReflectCallFuncNoArgs" ) args = make ([]reflect.Value, 0 ) methodValue.Call(args) }
要通过反射来调用起对应的方法,必须要先通过 reflect.ValueOf (interface) 来获取到 reflect.Value,得到 “反射类型对象” 后才能做下一步处理
reflect.Value.MethodByName 这.MethodByName,需要指定准确真实的方法名字,如果错误将直接 panic,MethodByName 返回一个函数值对应的 reflect.Value 方法的名字。
[]reflect.Value,这个是最终需要调用的方法的参数,可以没有或者一个或者多个,根据实际参数来定。
reflect.Value 的 Call 这个方法,这个方法将最终调用真实的方法,参数务必保持一致,如果 reflect.Value’Kind 不是一个方法,那么将直接 panic。
本来可以用 u.ReflectCallFuncXXX 直接调用的,但是如果要通过反射,那么首先要将方法注册,也就是 MethodByName,然后通过反射调用 methodValue.Call。
Demo Call method 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 package reflect_testimport ( "fmt" "reflect" "testing" ) type Spider interface { Crawl() string } type ASpider struct {}func (s *ASpider) Crawl () string { return "A" }func RunCrawl (spider Spider) string { reflectValue := reflect.ValueOf(spider) method := reflectValue.MethodByName("Crawl" ) value := method.Call(nil ) ret := value[0 ].Interface().(string ) return ret } func TestReflect (t *testing.T) { a := &ASpider{} ret := RunCrawl(a) fmt.Println(ret) }
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 ReflectFactory struct { Name string Age int } func (s *ReflectFactory) A (action string ) string { return action } func (s *ReflectFactory) B (action string ) string { return action } func main () { r := ReflectFactory{Name:"Ellison" } field := "Name" res := reflect.ValueOf(&r).Elem().FieldByName(field).String() fmt.Println(res) field2 := "B" valueS := reflect.ValueOf(&r) method := valueS.MethodByName(field2) params := []reflect.Value{ reflect.ValueOf(field), } res2 := method.Call(params)[0 ].String() fmt.Println(res2) }
struct 的反射 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 package mainimport ( "fmt" "reflect" ) type Student struct { Id int Name string } func (s Student) Hello () { fmt.Println("我是一个学生" ) } func main () { s := Student{Id: 1 , Name: "咖啡色的羊驼" } t := reflect.TypeOf(s) fmt.Println("这个类型的名称是:" , t.Name()) v := reflect.ValueOf(s) for i := 0 ; i < t.NumField(); i++ { key := t.Field(i) value := v.Field(i).Interface() fmt.Printf("第%d个字段是:%s:%v = %v \n" , i+1 , key.Name, key.Type, value) } for i:=0 ;i<t.NumMethod(); i++ { m := t.Method(i) fmt.Printf("第%d个方法是:%s:%v\n" , i+1 , m.Name, m.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 package mainimport ( "reflect" "fmt" ) type Student struct { Id int Name string } type People struct { Student } func main () { p := People{Student{Id: 1 , Name: "咖啡色的羊驼" }} t := reflect.TypeOf(p) fmt.Printf("%#v\n" , t.Field(0 )) fmt.Printf("%#v\n" , t.FieldByIndex([]int {0 , 1 })) v := reflect.ValueOf(p) fmt.Printf("%#v\n" , v.Field(0 )) }
Elem() Go语言程序中对指针获取反射对象时,可以通过 reflect.Elem() 方法获取这个指针指向的元素类型。这个获取过程被称为取元素,等效于对指针类型变量做了一个*
操作
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 package mainimport ( "fmt" "reflect" ) func main () { type cat struct {} ins := &cat{} typeOfCat := reflect.TypeOf(ins) fmt.Printf("name:'%v' kind:'%v'\n" ,typeOfCat.Name(), typeOfCat.Kind()) typeOfCat = typeOfCat.Elem() fmt.Printf("element name: '%v', element kind: '%v'\n" , typeOfCat.Name(), typeOfCat.Kind()) }
代码说明如下:
第 13 行,创建了cat结构体的实例,ins 是一个 *cat 类型的指针变量。
第 16 行,对指针变量获取反射类型信息。
第 19 行,输出指针变量的类型名称和种类。Go 语言的反射中对所有指针变量的种类都是 Ptr,但注意,指针变量的类型名称是空,不是 *cat。
第 22 行,取指针类型的元素类型,也就是 cat 类型。这个操作不可逆,不可以通过一个非指针类型获取它的指针类型。
第 25 行,输出指针变量指向元素的类型名称和种类,得到了 cat 的类型名称(cat)和种类(struct)。
reset struct field 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 package mainimport ( "fmt" "reflect" ) type Person struct { Name string Age string } func main () { var per Person val := reflect.ValueOf(&per) tp := reflect.TypeOf(per) for i:=0 ;i<val.Elem().NumField();i++{ if tp.Field(i).Name == "Name" { val.Elem().Field(i).SetString("zhao" ) } if tp.Field(i).Name == "Age" { val.Elem().Field(i).SetString("12" ) } } fmt.Println("~~~~~~~~~~~~~~~~~~" ) fmt.Println(per) }
dump map into struct 将map的数据放入struct
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 84 85 package reflect_valueimport ( "bytes" "encoding/gob" "errors" "fmt" "reflect" "strings" "testing" ) func Test2123 (t *testing.T) { mList := []map [string ]interface {}{ {"Id" : 213 , "Name" : "zhaoliu" , "Sex" : "男" }, {"Id" : 56 , "Name" : "zhangsan" , "Sex" : "男" }, {"Id" : 7 , "Name" : "lisi" , "Sex" : "女" }, {"Id" : 978 , "Name" : "wangwu" , "Sex" : "男" }, } type User struct { Id int Name string Sex string } users := []*User{} mapToStruct(mList, &users) fmt.Printf("users: %+v\n" , users) } func mapToStruct (mList []map [string ]interface {}, model interface {}) (err error) { val := reflect.Indirect(reflect.ValueOf(model)) typ := val.Type() for _, r := range mList { mVal := reflect.Indirect(reflect.New(typ.Elem().Elem())).Addr() for key, val := range r { err = setField(mVal.Interface(), key, val) if err != nil { return err } } val = reflect.Append(val, mVal) } DeepCopy(model, val.Interface()) return err } func setField (obj interface {}, name string , value interface {}) error { sl := strings.Split(name, "" ) sl[0 ] = strings.ToUpper(sl[0 ]) name = strings.Join(sl, "" ) structValue := reflect.ValueOf(obj).Elem() structFieldValue := structValue.FieldByName(name) if !structFieldValue.IsValid() { return fmt.Errorf("No such field: %s in obj" , name) } if !structFieldValue.CanSet() { return fmt.Errorf("Cannot set %s field value" , name) } structFieldType := structFieldValue.Type() val := reflect.ValueOf(value) if structFieldType != val.Type() { return errors.New("type is err" ) } structFieldValue.Set(val) return nil } func DeepCopy (dst, src interface {}) error { var buf bytes.Buffer if err := gob.NewEncoder(&buf).Encode(src); err != nil { return err } return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) }
dump interface into struct 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 package mainimport ( "fmt" "reflect" ) type Body struct { Age int Name string } type Message struct { Body interface {} } func main () { tmp := &Body{ Age: 10086 , Name: "obgnail" , } message := &Message{Body: tmp} body := &Body{} RVmessage := reflect.ValueOf(message.Body).Elem() reflect.ValueOf(body).Elem().Set(RVmessage) fmt.Println(body) }
reference