• C级总销量迫近A4L 宝马3系乏力 2019-03-21
  • 西安楼市进入短暂调整期 摇号细则近日将出 2019-03-21
  • 北京学习十九大精神--北京频道--人民网 2019-03-15
  • 临潼区马额镇庙张村西坡组农民饮用黄泥水 2019-03-13
  • 我早就说过,任何时候都不能对美国抱有幻想。否则就是白痴。 2019-03-11
  • 安徽加大就业脱贫力度 确保贫困户至少一人就业 2019-03-07
  • 环保督察点名批评 河北两市治理大沙河河堤垃圾带 2019-02-25
  • E3 2019展会日期确定 今年E3参加人数约69200人 2019-02-25
  • 外贸创新举措 让开放惠及世界 2019-02-22
  • 好莱坞环球影城“功夫熊猫”主题剧院开放 2019-02-22
  • 阜阳五中成功举办第四届社团文化艺术节文艺汇演 2019-02-21
  • 通用航空产业军民融合实现全方位突破 2019-02-21
  • 高培勇任中国社会科学院副院长(图简历) 2019-02-11
  • 撸主脑残,重度三级,鉴定完毕。[哈哈] 2019-02-05
  • 《云冈石窟保护条例》8月实施 刻划涂污文物最高罚200元--旅游频道 2019-02-05
  • Golang语言社区 + 关注
    手机版

    Goalng下的反射??閞eflect学习使用

    1. 神奇公式秒杀全国11选5>
    2. Golang语言社区>
    3. 博客>
    4. 正文

    Goalng下的反射??閞eflect学习使用

    技术小能手 2018-11-14 10:53:26 浏览5384 评论0

    神奇公式秒杀全国11选5 www.bjux.net 摘要: 反射reflection 反射 ?●??可以大大提高程序的灵活性,使得interface{}有更大的发挥余地?●??反射使用TypeOf和ValueOf函数从接口中获取目标对象信息?●??反射会将匿名字段作为独立字段(匿名字段的本质)?●??想要利用反射修改对象状态,前提是interface.

    反射reflection

    反射

    ?●??可以大大提高程序的灵活性,使得interface{}有更大的发挥余地
    ?●??反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
    ?●??反射会将匿名字段作为独立字段(匿名字段的本质)
    ?●??想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface
    ?●??通过反射可以"动态" 调用方法

    常用的类型、函数和方法

    
    
    1//返回动态类型i的类型,如果i是一个空结构体类型,TypeOf将返回nil
    2func TypeOf(i interface{}) Type
    3
    4//Type 接口类型
    5type Type interface {
    6 Align() int
    7 FieldAlign() int
    8 //指定结构体中方法的下标,返回某个方法的对象,需要注意的是返回的Method是一个独立的结构体
    9 Method(int) Method
    10 /*
    11 type Method struct {
    12 Name string
    13 PkgPath string
    14 Type Type
    15 Func Value
    16 Index int
    17 }
    18 */
    19
    20
    21 MethodByName(string) (Method, bool)
    22
    23 //返回该结构体类型的方法下标
    24 NumMethod() int
    25 //返回类型的名称,即动态类型i的名称
    26 Name() string
    27 PkgPath() string
    28 Size() uintptr
    29 String() string
    30 Kind() Kind
    31 Implements(u Type) bool
    32 AssignableTo(u Type) bool
    33 ConvertibleTo(u Type) bool
    34 Comparable() bool
    35 Bits() int
    36 ChanDir() ChanDir
    37 IsVariadic() bool
    38 Elem() Type
    39 //返回结构体类型第i个字段
    40 Field(i int) StructField
    41 //StructField结构体
    42 //type StructField struct {
    43 // Name string
    44 // PkgPath string
    45 // Type Type
    46 // Tag StructTag
    47 // Offset uintptr
    48 // Index []int
    49 // Anonymous bool
    50
    51 //根据结构体字段索引获取嵌入字段的结构体信息
    52 FieldByIndex(index []int) StructField
    53
    54 FieldByName(name string) (StructField, bool)
    55 FieldByNameFunc(match func(string) bool) (StructField, bool)
    56 In(i int) Type
    57 Key() Type
    58 Len() int
    59 //返回动态类型i(结构体字段)的字段总数
    60 NumField() int
    61 NumIn() int
    62 NumOut() int
    63 Out(i int) Type
    64}
    65
    66//返回接口i的一个初始化的新值.ValueOf(nil)返回一个零值
    67func ValueOf(i interface{}) Value
    68
    69// Value结构体
    70type Value struct {
    71
    72}
    73// Value结构体的一些方法
    74// 返回结构体v中的第i个字段。如果v的类型不是结构体或者i超出了结构体的范围,则会出现panic
    75func (v Value) Field(i int) Value
    76
    77//以接口类型返回v的当前值
    78func (v Value) Interface() (i interface{})
    79//等价于.
    80var i interface{} = (v's underlying value)
    81
    82
    83//通过反射方式修改结构体对象的一些方法
    84
    85//返回接口v包含或者指针v包含的值
    86func (v Value) Elem() Value
    87//判断该接口v是否可以被set修改
    88func (v Value) CanSet() bool
    89
    90//使用另外一个反射接口去修改反射值
    91func (v Value) Set(x Value)
    92//其他不同类型的Set
    93func (v Value) SetBool(x bool)
    94func (v Value) SetBytes(x []byte)
    95func (v Value) SetFloat(x float64)
    96func (v Value) SetInt(x int64)
    97//设置结构体对象v的长度为n
    98func (v Value) SetLen(n int)
    99func (v Value) SetString(x string)
    100
    101
    102//一些辅助方法
    103//返回反射结构体的Value的类型.如果v为零值,IsValid将返回false
    104func (v Value) Kind() Kind
    105//判断value是否为有效值,通常用在判断某个字段是否在反射体的Value中
    106func (v Value) IsValid() bool
    107
    108//Kind常量
    109type Kind uint
    110const (
    111 Invalid Kind = iota
    112 Bool
    113 Int
    114 Int8
    115 Int16
    116 Int32
    117 Int64
    118 Uint
    119 Uint8
    120 Uint16
    121 Uint32
    122 Uint64
    123 Uintptr
    124 Float32
    125 Float64
    126 Complex64
    127 Complex128
    128 Array
    129 Chan
    130 Func
    131 Interface
    132 Map
    133 Ptr
    134 Slice
    135 String
    136 Struct
    137 UnsafePointer
    138)
    139

    反射的基本操作

    通过反射来获取结构体字段的名称以及其他相关信息。

    
    
    1$ cat test-reflect.go
    2package main
    3import (
    4 "fmt"
    5 "reflect"
    6)
    7
    8//定义结构体
    9type User struct{
    10 Id int
    11 Name string
    12 Age int
    13 }
    14//定义结构体方法
    15func (u User) Hello(){
    16 fmt.Println("Hello xuxuebiao")
    17 }
    18
    19func main() {
    20 u := User{1,"bgops",25}
    21 Info(u)
    22 u.Hello()
    23}
    24
    25//定义一个反射函数,参数为任意类型
    26func Info(o interface{}) {
    27 //使用反射类型获取o的Type,一个包含多个方法的interface
    28 t := reflect.TypeOf(o)
    29 //打印类型o的名称
    30 fmt.Println("type:",t.Name())
    31
    32 //使用反射类型获取o的Value,一个空的结构体
    33 v := reflect.ValueOf(o)
    34 fmt.Println("Fields:")
    35
    36 //t.NumField()打印结构体o的字段个数(Id,Name,Age共三个)
    37 for i :=0;i< t.NumField();i++{
    38 //根据结构体的下标i来获取结构体某个字段,并返回一个新的结构体
    39 /**
    40 type StructField struct {
    41 Name string
    42 PkgPath string
    43 Type Type
    44 Tag StructTag
    45 Offset uintptr
    46 Index []int
    47 Anonymous bool
    48 }
    49 **/
    50 f := t.Field(i)
    51
    52 //使用结构体方法v.Field(i)根据下标i获取字段Value(Id,Name,Age)
    53 //在根据Value的Interface()方法获取当前的value的值(interface类型)
    54 val := v.Field(i).Interface()
    55 fmt.Printf("%6s:%v = %v\n",f.Name,f.Type,val)
    56 }
    57
    58 //使用t.NumMethod()获取所有结构体类型的方法个数(只有Hello()一个方法)
    59 //接口Type的方法NumMethod() int
    60 for i := 0;i < t.NumMethod();i++ {
    61 //使用t.Method(i)指定方法下标获取方法对象。返回一个Method结构体
    62 //Method(int) Method
    63 m := t.Method(i)
    64 //打印Method结构体的相关属性
    65 /*
    66 type Method struct {
    67 Name string
    68 PkgPath string
    69 Type Type
    70 Func Value
    71 Index int
    72 }
    73 */
    74 fmt.Printf("%6s:%v\n",m.Name,m.Type)
    75 }
    76 }
    77
    78$ go run test-reflect.go
    79type: User
    80Fields:
    81 Id:int = 1
    82 Name:string = bgops
    83 Age:int = 25
    84 Hello:func(main.User)
    85Hello xuxuebiao
    86

    注意:我们上面的示例是使用值类型进行进行反射构造的。如果是指针类型的话,我们需要使用reflect.Struct字段进行判断接口类型的Kind()方法

    
    
    1if k := t.Kind();k != reflect.Struct {
    2 fmt.Println("非值类型的反射")
    3 return
    4}

    匿名字段的反射以及嵌入字段

    注意:反射会将匿名字段当做独立的字段去处理,需要通过类型索引方式使用FieldByIndex方法去逐个判断

    
    
    1//根据指定索引返回对应的嵌套字段
    2FieldByIndex(index []int) StructField
    3
    4type StructField struct {
    5 Name string
    6 PkgPath string
    7 Type Type
    8 Tag StructTag
    9 Offset uintptr
    10 Index []int
    11 Anonymous bool //是否为匿名字段
    12}

    示例:

    
    
    1$ cat anonymous-reflect.go
    2package main
    3import (
    4 "fmt"
    5 "reflect"
    6)
    7
    8type User struct {
    9 Id int
    10 Name string
    11 Age int
    12}
    13
    14type Manager struct {
    15 User
    16 title string
    17}
    18
    19func main() {
    20 //注意匿名字段的初始化操作
    21 m := Manager{User: User{1,"biaoge",24},title:"hello biao"}
    22 t := reflect.TypeOf(m)
    23
    24 fmt.Printf("%#v\n",t.FieldByIndex([]int{0}))
    25 fmt.Printf("%#v\n",t.FieldByIndex([]int{1}))
    26 fmt.Printf("%#v\n",t.FieldByIndex([]int{0,0}))
    27 fmt.Printf("%#v\n",t.FieldByIndex([]int{0,1}))
    28
    29}
    30
    31$ go run anonymous-reflect.go
    32reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x97260), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
    33reflect.StructField{Name:"title", PkgPath:"main", Type:(*reflect.rtype)(0x8bda0), Tag:"", Offset:0x20, Index:[]int{1}, Anonymous:false}
    34reflect.StructField{Name:"Id", PkgPath:"", Type:(*reflect.rtype)(0x8b8a0), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false}
    35reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x8bda0), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false}

    通过反射修改目标对象

    通过反射的方式去修改对象的某个值。需要注意的亮点是,首先,需要找到对象相关的名称,其次需要找到合适的方法去修改相应的值。

    
    
    1$ cat mod-value-reflect.go
    2package main
    3import (
    4 "fmt"
    5 "reflect"
    6)
    7
    8func main() {
    9 x := 123
    10 v := reflect.ValueOf(&x)
    11 v.Elem().SetInt(5256)
    12 fmt.Println(x)
    13}
    14
    15$ go run mod-value-reflect.go
    165256

    修改I的时候需要找到对象字段的名称;并且判断类型,使用相对正确的类型修改值

    
    
    1v.FieldByName("Name");f.Kind() == reflect.String {
    2 f.SetString("test string")
    3}

    判断是否找到正确的字段名称:

    
    
    1f := v.FieldByName("Name1")
    2//判断反射对象Value中是否找到Name1字段
    3if !f.IsValid() {
    4 fmt.Println("bad field")
    5 return
    6}

    示例:

    
    
    1$ cat mod-value-reflect.go
    2package main
    3import (
    4 "fmt"
    5 "reflect"
    6)
    7
    8type User struct {
    9 Id int
    10 Name string
    11 Age int
    12}
    13
    14//使用反射方式对结构体对象的修改有两个条件
    15//1.通过指针
    16//2.必须是可set的方法
    17func main() {
    18 num := 123
    19 numv := reflect.ValueOf(&num)
    20 //通过Value的Elem()和SetX()方法可直接对相关的对象进行修改
    21 numv.Elem().SetInt(666)
    22 fmt.Println(num)
    23
    24 u := User{1,"biao",24}
    25 uu := reflect.ValueOf(&u)
    26 //Set()后面的必须是值类型
    27 //func (v Value) Set(x Value)
    28 test := User{2,"bgops",2}
    29 testv := reflect.ValueOf(test)
    30 uu.Elem().Set(testv)
    31 fmt.Println("Change the test to u with Set(x Value)",uu)
    32
    33 //此时的U已经被上面那个uu通过指针的方式修改了
    34 Set(&u)
    35 fmt.Println(u)
    36}
    37
    38func Set(o interface{}) {
    39 v := reflect.ValueOf(o)
    40 //判断反射体值v是否是Ptr类型并且不能进行Set操作
    41 if v.Kind() == reflect.Ptr && ! v.Elem().CanSet() {
    42 fmt.Println("xxx")
    43 return
    44 //初始化对象修改后的返回值(可接受v或v的指针)
    45 } else {
    46 v = v.Elem()
    47 }
    48 //按照结构体对象的名称进行查找filed,并判断类型是否为string,然后进行Set
    49 if f := v.FieldByName("Name"); f.Kind() == reflect.String {
    50 f.SetString("BYBY")
    51 }
    52 }
    53
    54$ go run mod-value-reflect.go
    55666
    56Change the test to u with Set(x Value) &{2 bgops 2}
    57{2 BYBY 2}

    通过反射进行动态方法的调用

    使用反射的相关知识进行方法的动态调用

    
    
    1$ cat method-reflect.go
    2package main
    3import (
    4 "fmt"
    5 "reflect"
    6)
    7
    8type User struct {
    9 Id int
    10 Name string
    11 Age int
    12}
    13
    14func (u User) Hello(name string,id int) {
    15 fmt.Printf("Hello %s,my name is %s and my id is %d\n",name,u.Name,id)
    16}
    17
    18func main() {
    19 u := User{1,"biaoge",24}
    20 fmt.Println("方法调用:")
    21 u.Hello("xuxuebiao",121)
    22
    23 //获取结构体类型u的Value
    24 v := reflect.ValueOf(u)
    25 //根据方法名称获取Value中的方法对象
    26 mv := v.MethodByName("Hello")
    27
    28 //构造一个[]Value类型的变量,使用Value的Call(in []Value)方法进行动态调用method
    29 //这里其实相当于有一个Value类型的Slice,仅一个字段
    30 args := []reflect.Value{reflect.ValueOf("xuxuebiao"),reflect.ValueOf(5256)}
    31 fmt.Println("通过反射动态调用方法:")
    32 //使用Value的Call(in []Value)方法进行方法的动态调用
    33 //func (v Value) Call(in []Value) []Value
    34 //需要注意的是当v的类型不是Func的化,将会panic;同时每个输入的参数args都必须对应到Hello()方法中的每一个形参上
    35 mv.Call(args)
    36
    37}
    38
    39$ go run method-reflect.go
    40方法调用:
    41Hello xuxuebiao,my name is biaoge and my id is 121
    42通过反射动态调用方法:
    43Hello xuxuebiao,my name is biaoge and my id is 5256

    原文发布时间为:2018-11-13
    本文作者:BGbiao
    本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“Golang语言社区”。
    【云栖快讯】一站式开发者服务,海量学习资源免费学  详情请点击

    网友评论

  • C级总销量迫近A4L 宝马3系乏力 2019-03-21
  • 西安楼市进入短暂调整期 摇号细则近日将出 2019-03-21
  • 北京学习十九大精神--北京频道--人民网 2019-03-15
  • 临潼区马额镇庙张村西坡组农民饮用黄泥水 2019-03-13
  • 我早就说过,任何时候都不能对美国抱有幻想。否则就是白痴。 2019-03-11
  • 安徽加大就业脱贫力度 确保贫困户至少一人就业 2019-03-07
  • 环保督察点名批评 河北两市治理大沙河河堤垃圾带 2019-02-25
  • E3 2019展会日期确定 今年E3参加人数约69200人 2019-02-25
  • 外贸创新举措 让开放惠及世界 2019-02-22
  • 好莱坞环球影城“功夫熊猫”主题剧院开放 2019-02-22
  • 阜阳五中成功举办第四届社团文化艺术节文艺汇演 2019-02-21
  • 通用航空产业军民融合实现全方位突破 2019-02-21
  • 高培勇任中国社会科学院副院长(图简历) 2019-02-11
  • 撸主脑残,重度三级,鉴定完毕。[哈哈] 2019-02-05
  • 《云冈石窟保护条例》8月实施 刻划涂污文物最高罚200元--旅游频道 2019-02-05