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中的反射知识进行了简单实践,具体内容如下:
涉及到的反射知识点补充
reflect.ValueOf()的返回值类型为reflect.Value,表示值的真实内容。
var i
int
=
123
var s =
"abc"
fmt.Println(reflect.ValueOf(i))
// 123
fmt.Println(reflect.ValueOf(s))
// abc
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
}
它返回的是对象的基本类型,例如 Float32、Float64、int32、int64、Slice、Bool、Complex64、Array、chan、Func、Interface、Map 等等。
前者放回的是一个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
}
前者返回一个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 删除。