go反射实例
需求分析:
如在rocketmq的网络通信中,所有通信数据包以如下形式传输: (注:rocketmq的java结构体,这里使用了go形式表示)
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
}
只要实现了CustomHeader接口的结构体,调用DecodeCustomHeader方法,就可以获取对应的数据了。另外根据业务需要,可以扩展 reflectSturctSetField 方法。(完)
go反射实例的更多相关文章
- ObjectTools反射实例
ObjectTools反射实例 package com.shitou.deposit.chinapnr.utils; import org.apache.commons.logging.Log; im ...
- 类的反射实例(servlet的抽取)
类的反射实例 具体以后我们写的时候不用写BaseServlet,因为各种框架都已经给我们写好了 所以,user对应的servlet的界面长这样:
- C#反射实例应用--------获取程序集信息和通过类名创建类实例
AppDomain.CurrentDomain.GetAssemblies();获取程序集,但是获取的只是已经加载的dll,引用的获取不到. System.Reflection.Assembly.Ge ...
- PHP API反射实例
*反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复杂,可扩展的应用.其用途如:自动加载插件,自动生成文档,甚至可用来扩充PHP语言.php反射api由若干类组成,可帮助我们用来 ...
- java反射 实例
首先介绍几个概念: 1.Java反射的概念 反射含义:可以获取正在运行的Java对象. 2.Java反射的功能 1)可以判断运行时对象所属的类 2)可以判断运行时对象所具有的成员变量和方法 3)通过反 ...
- c# 类的反射实例 (GetType().Invoke().GetMethod().CreateInstance())
原文:http://www.cnblogs.com/chenwei19/archive/2009/02/04/1384034.html Class1和Form 窗体在同一个命名空间 using Sys ...
- C#反射实例(一) 利用反射使用类库
在网上查找了不少的资料,可以说大同小异,概念性的东西网上一搜一堆,今天把反射的东西整理了一下,供大家使用,我保证我这里是最全面的东西,当然也是基础的东西,在学好了这一切的基础上,大家可以学习反射的具体 ...
- Java 反射实例
实体类:Userpackage com.reflect.model; public class User{ private User(int id, String username, String p ...
- C# 反射实例
1.接口 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ...
随机推荐
- MySQL-Proxy 读写分离、同步延时问题解决方案
MySQL-Proxy 读写分离.同步延时问题解决方案 使用MySQL将读写请求转接到主从Server. 一 安装MySQL Proxy MySQL Proxy的二进制版非常方便,下载解压缩后即用. ...
- as3 阻止后续侦听器
public class Test1 extends Sprite { private var spr:Sprite; private var spr2:Sprite; public function ...
- Linux环境下搭建Git仓库
1.安装Git $ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel $ yum ...
- 0基础自学php教程
轻松搞定网页设计之html 一.HTML介绍 1. HTML概念 HTML(Hyper Text Markup Language),即超文本标记语言.是目前网络上应用最为广泛的语言,是构成网页文档的主 ...
- 如何配置Python环境
(1) 下载:请在Python官网下载页面(https://www.python.org/downloads/)选择合适的版本(建议选择3.5.2版)的链接,在该版本的下载页面选择合适的安装文件:64 ...
- java bean 合并
package com.hainabo.mgcmall.util; import java.beans.BeanInfo;import java.beans.Introspector;import j ...
- 018:InnoDB 存储引擎、表空间
目录 一.InnoDB 存储引擎 1. InnoDB的历史 2. InnoDB的特点 3. InnoDB存储引擎的文件 3.1 概述 3.2 InnoDB - 表空间 3.3 General表空间 3 ...
- python学习(二十) Python 中的比较:is 与 ==
Python 中的比较:is 与 == 在 Python 中会用到对象之间比较,可以用 ==,也可以用 is .但是它们的区别是什么呢? is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象 ...
- node的close
在http.ServerResponse对象的end方法被调用之前,如果连接被中断,将触发http.ServerResponse对象的close事件. var http=require("h ...
- sql,groupby以后取每组前三行
--> 生成测试数据: #TIF OBJECT_ID('tempdb.dbo.#T') IS NOT NULL DROP TABLE #T CREATE TABLE #T (ID VARCHAR ...