首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang —— 反射

Golang —— 反射

原创
作者头像
舒琪
修改2019-04-15 10:38:21
6580
修改2019-04-15 10:38:21
举报
文章被收录于专栏:FLINKFLINK

package main

import (

"fmt"

"reflect"

)

func main() {

bill := &User{"bill", "bill@163.com"}

object := reflect.ValueOf(bill)

// myref := object.Elem()

// typeOfType := myref.Type()

// for i := 0; i < myref.NumField(); i++ {

// field := myref.Field(i)

// fmt.Printf("%d. %s %s = %v \n", i, typeOfType.Field(i).Name, field.Type(), field.Interface())

// }

// tonydon.SayHello()

v := object.MethodByName("Notify")

v.Call([]reflect.Value{})

}

type User struct {

name string

email string

}

func (u *User) Notify() {

fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)

}

func (u *User) Hello() {

fmt.Println("hello Sending user email to")

}

输出:Sending user email to bill<bill@163.com> 成功: 进程退出代码 0.

package main

import (

"fmt"

"reflect"

)

func main() {

tonydon := &User{"TangXiaodong", 100, "0000123"}

object := reflect.ValueOf(tonydon)

myref := object.Elem()

typeOfType := myref.Type()

for i:=0; i<myref.NumField(); i++{

field := myref.Field(i)

fmt.Printf("%d. %s %s = %v \n", i, typeOfType.Field(i).Name, field.Type(), field.Interface())

}

tonydon.SayHello()

v := object.MethodByName("SayHello")

v.Call([]reflect.Value{})

}

type User struct {

Name string

Age int

Id string

}

3:传值

package main

import (

"fmt"

"reflect"

)

// 普通函数

func add(a, b int) int {

return a + b

}

func main() {

// 将函数包装为反射值对象

funcValue := reflect.ValueOf(add)

// 构造函数参数, 传入两个整型值

paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}

// 反射调用函数

retList := funcValue.Call(paramList)

// 获取第一个返回值, 取整数值

fmt.Println(retList[0].Int())

}

基本概念:

type RemotingCommand struct { //header Code int `json:"code"` Language string `json:"language"` Version int `json:"version"` Opaque int32 `json:"opaque"` Flag int `json:"flag"` Remark string `json:"remark,omitempty"` ExtFields map[string]string `json:"extFields"` //body Body []byte `json:"body,omitempty"` }

其中,ExtFields 表示用户自定义数据包,如:在某次通信中传输的 ExtFields 的内容如下,接收对象为 MyResponseHeader 型。

//ExtFields 数据内容

extFields := make(map[string]string)

extFields ["result"] = "true"

extFields ["answer"] = "1234"

//MyResopnseHeader 接口体

type MyResponseHeader struct {

Result bool

Answer int64

}

将 “extFields ” 转化为 MyResponseHeader 型过程中,需要将string型数据分别转换为 bool、int64等类型。

另外,不同的remotingCommand包接收到数据后需要解析成不同的结构体数据, 如何使用一个方式与统一解析数据呢? 解决这个问题需要用到反射。本文根据这个问题,对go中的反射知识进行了简单实践,具体内容如下:

涉及到的反射知识点补充

1.reflect.Value

reflect.ValueOf()的返回值类型为reflect.Value,表示值的真实内容。

var i int = 123

var s = "abc"

fmt.Println(reflect.ValueOf(i)) // 123

fmt.Println(reflect.ValueOf(s)) // abc

2.reflect.Value值的设置

go中不能直接对Value进行赋值操作,如对上述变量 s 进行赋值,首先需要拿到 s 值的指针,然后拿到该指针的reflect.Value,指针的reflect.Value调用Value.Elem()后对对应到 s 值对象,继而可以对 s 进行赋值操作。

value赋值的例子:

func main(){

var i int = 123

fe := reflect.ValueOf(&i).Elem()  //必须是指针的Value才能调用Elem

fmt.Println(fe)         // 123

fmt.Println(fe.CanSet()) // true

fe.SetInt(456)

fmt.Println(i) //456

}

3.reflect.Type.Kind 与 reflect.Value.Kind

它返回的是对象的基本类型,例如 Float32、Float64、int32、int64、Slice、Bool、Complex64、Array、chan、Func、Interface、Map 等等。

4.reflect.Type.Filed 与 relfect.Type.Filed

前者放回的是一个StructFiled对象。后者返回的还是一个Value对象

type StructField struct {

Name string         // name 常用

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

}

5.reflect.Type.FiledByName 与 reflect.Value.FileByName

前者返回一个StructFiled对象,后者返回的还是一个Value对象

具体实现过程

参考rocketmq的思路,先定义一个 CustomHeader接口,自定义包实现该接口,然后定义一个解析包的方法,该方法中包括go反射的运用。

自定义数据包:

type CustomHeader interface {

CheckFields() error

}

结构体实现了 CustomHeader 接口:

type MyResponseHeader struct {

Result bool

Answer int64

}

func (t *MyResponseHeader) CheckFields() error {

return nil

}

转化测试:

//ExtFields 数据内容

extFields := make(map[string]string)

extFields ["result"] = "true"

extFields ["answer"] = "1234"

err := DecodeCustomHeader(extFields, myResponseHeader)

if err != nil {

  panic(err.Error())

}

fmt.Printf("myResponseHeader.Result = %v \nmyResponseHeader.Answer = %d\n", myResponseHeader.Result, myResponseHeader.Answer)

结果:

myResponseHeader.Result = true  
myResponseHeader.Answer = 1234

DecodeCustomHeader代码如下:

func DecodeCustomHeader(extFields map[string]string, commandCustomHeader CustomHeader) error { structValue := reflect.ValueOf(commandCustomHeader).Elem() for k, v := range extFields { err := reflectSturctSetField(structValue, firstLetterToUpper(k), v) if err != nil { return err } } return nil } // 支持string int8 int16 int int32 int64 uint8 uint16 uint32 uint64 bool,非string类型将进行转换 func reflectSturctSetField(structValue reflect.Value, name string, value string) error { structFieldValue := structValue.FieldByName(name) if !structFieldValue.IsValid() { return errors.Errorf("No such field: %s in obj", name) } if !structFieldValue.CanSet() { return errors.Errorf("Cannot set %s field value", name) } structFieldType := structFieldValue.Type() switch structFieldType.Kind() { case reflect.String: structFieldValue.SetString(value) case reflect.Int8: fallthrough case reflect.Int16: fallthrough case reflect.Int32: fallthrough case reflect.Int64: fallthrough case reflect.Int: ival, err := strconv.ParseInt(value, 10, 64) if err != nil { return errors.Wrap(err, 0) } structFieldValue.SetInt(ival) case reflect.Uint8: fallthrough case reflect.Uint16: fallthrough case reflect.Uint32: fallthrough case reflect.Uint64: ival, err := strconv.ParseUint(value, 10, 64) if err != nil { return errors.Wrap(err, 0) } structFieldValue.SetUint(ival) case reflect.Bool: bval, err := strconv.ParseBool(value) if err != nil { return errors.Wrap(err, 0) } structFieldValue.SetBool(bval) default: return errors.Errorf("Provided value type didn't match obj field type") } return nil } // 首字母大写 func firstLetterToUpper(s string) string { if len(s) > 0 { b := []byte(s) if b[0] >= 'a' && b[0] <= 'z' { b[0] = b[0] - byte(32) s = string(b) } } return s }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.reflect.Value
  • 2.reflect.Value值的设置
  • 3.reflect.Type.Kind 与 reflect.Value.Kind
  • 4.reflect.Type.Filed 与 relfect.Type.Filed
  • 5.reflect.Type.FiledByName 与 reflect.Value.FileByName
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档