golang json 包简单分析
首先上代码:
func main() { b := true a1, _ := json.Marshal(b) a2, _ := Marshal(b) fmt.Println(string(a1)) fmt.Println(string(a2))}
输出:
truetrue
以最简单的单个bool 类型的序列化为例,我们来搞清楚json 包里面的调用栈如下:
从入口出发,第一个方法是:
func Marshal(v interface{}) ([]byte, error) { e := &encodeState{} err := e.marshal(v) if err != nil { return nil, err } return e.Bytes(), nil}
这里没有什么特殊,只是为了引出encodeState
// An encodeState encodes JSON into a bytes.Buffer.type encodeState struct { bytes.Buffer // accumulated output scratch [64]byte}
这里的Buffer就是我们所有输出字节的Buffer,再继续往里面走
func (e *encodeState) marshal(v interface{}) (err error) { defer func() { if r := recover(); r != nil { if _, ok := r.(runtime.Error); ok { panic(r) } if s, ok := r.(string); ok { panic(s) } err = r.(error) } }() e.reflectValue(reflect.ValueOf(v)) return nil}
这里我们看到了反射获得值,个人认为这里的命名不太科学,不过无妨,继续往下走。
func valueEncoder(v reflect.Value) encoderFunc { if !v.IsValid() { return invalidValueEncoder } return typeEncoder(v.Type())}
这里通过反射的类型,获得和使用该类型的序列化方法.顺便还做了把缓存。
func typeEncoder(t reflect.Type) encoderFunc { encoderCache.RLock() f := encoderCache.m[t] encoderCache.RUnlock() if f != nil { return f } // To deal with recursive types, populate the map with an // indirect func before we build it. This type waits on the // real func (f) to be ready and then calls it. This indirect // func is only used for recursive types. encoderCache.Lock() if encoderCache.m == nil { encoderCache.m = make(map[reflect.Type]encoderFunc) } var wg sync.WaitGroup wg.Add(1) encoderCache.m[t] = func(e *encodeState, v reflect.Value, quoted bool) { wg.Wait() f(e, v, quoted) } encoderCache.Unlock() // Compute fields without lock. // Might duplicate effort but won't hold other computations back. f = newTypeEncoder(t, true) wg.Done() encoderCache.Lock() encoderCache.m[t] = f encoderCache.Unlock() return f}
至于具体的Encoder,通过Type很容易找到。
switch t.Kind() { case reflect.Bool: return boolEncoder case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return intEncoder case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return uintEncoder case reflect.Float32: return float32Encoder case reflect.Float64: return float64Encoder case reflect.String: return stringEncoder case reflect.Interface: return interfaceEncoder case reflect.Struct: return newStructEncoder(t) case reflect.Map: return newMapEncoder(t) case reflect.Slice: return newSliceEncoder(t) case reflect.Array: return newArrayEncoder(t) case reflect.Ptr: return newPtrEncoder(t) default: return unsupportedTypeEncoder
最终我们这里的boolEncoder的实现
func boolEncoder(e *encodeState, v reflect.Value, quoted bool) { if quoted { e.WriteByte('"') } if v.Bool() { e.WriteString("true") } else { e.WriteString("false") } if quoted { e.WriteByte('"') }}
当然这个只是一个最简单的示例,里面很多实现的细节可以推敲。这里只是把这种序列化的方式归结为类型反射+缓存的方式。
备注
这个系列不是一个大而全的package api 指南,只包括作者认为最常见的使用方式。抗议无效。
golang json 包简单分析的更多相关文章
- [golang] 抓包注入分析
视频信息 Packet Capture, Analysis, and Injection with Goby John Leonat GopherCon 2016 https://www.youtub ...
- golang flag包简单例子
package main import ( "flag" "fmt" ) var workers int; func main() { flag.IntVar( ...
- Golang的json包
encoding/json encoding/json是官方提供的标准json, 实现RFC 7159中定义的JSON编码和解码.使用的时候需要预定义struct,原理是通过reflection和in ...
- Golang fmt包使用小技巧
h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...
- 易企秀H5 json配置文件解密分析
最近需要参考下易企秀H5的json配置文件,发现已经做了加密,其实前端的加密分析起来只是麻烦点. 抓包分析 先看一个H5: https://h5.eqxiu.com/s/XvEn30op F12可以看 ...
- 开源网络抓包与分析框架学习-Packetbeat篇
开源简介packbeat是一个开源的实时网络抓包与分析框架,内置了很多常见的协议捕获及解析,如HTTP.MySQL.Redis等.在实际使用中,通常和Elasticsearch以及kibana联合使用 ...
- Golang测试包
Golang测试包 golang自带了测试包(testing),直接可以进行单元测试.性能分析.输出结果验证等.简单看着官方文档试了试,总结一下: 目录结构和命令 使用golang的测试包,需要遵循简 ...
- Golang JSON操作汇总
直接把结构体编码成json数据 package main import ( "encoding/json" "fmt" _ "os" ) t ...
- Golang : pflag 包简介
笔者在前文中介绍了 Golang 标准库中 flag 包的用法,事实上有一个第三方的命令行参数解析包 pflag 比 flag 包使用的更为广泛.pflag 包的设计目的就是替代标准库中的 flag ...
随机推荐
- ZJOIDay2T1 BB题解
讲道理我是调不出来了... 考虑对序列按下标维护每个节点最后的树. 那么 改操作点 - 把一段连续的节点改父亲 加点/删点(注意拆成两个操作了) 插儿子 那么用seg维护一下下标, 用ETT维护Dep ...
- 巧用linux服务器的/dev/shm/,如果合理使用,可以避开磁盘IO不给力,提高网站访问速度。
巧用linux服务器的/dev/shm/ 巧用linux服务器的/dev/shm/,如果合理使用,可以避开磁盘IO不给力,提高网站访问速度. 首先让我们认识一下,什么是tmpfs和/dev/shm/? ...
- DevStack安装时报“download of get-pip.py failed”
ref from : http://www.voidcn.com/blog/ldli8979/article/p-5005958.html 这个可能会有多种原因造成.网上搜了一下,有人说需要手动下载, ...
- Angularjs与bootstrap.datetimepicker结合实现日期选择器
http://www.lovelucy.info/angularjs-best-practices.html http://damoqiongqiu.iteye.com/blog/1917971 ht ...
- C# webservice 编写、发布、调用
采用的工具VS2010生成工程 1. 生成webservice工程:建 ASP.NET 空WEB 应用程序. 2. 在建好的ASP.NET 空WEB应用程序中新建项“web 服务”. 完成上述内容工程 ...
- poj 1010
http://poj.org/problem?id=1010 题意:给你n种邮票的价值,到0结束,这些邮票价值有可能相同,但是形状是不同的. 还有给你m个收藏家所需要收藏的邮票的总价格.到0结束. 每 ...
- centos7 systemctl 启动 Redis 失败
转自:http://sloger.info/posts/systemd-failed-to-start-redis-in-gentoo 今天启动 Redis 时阻塞很长时间,之后显示启动失败,启动状态 ...
- C++实现双缓冲
首先声明下,这篇资料也是整理别人的资料的基础上,总结来的. 在图形图像处理过程中,双缓冲技术是一种比较常见的技术.窗体在响应WM_PAINT消息时,需要对图像进行绘制处理.如果图像绘制次数过多,重绘过 ...
- iOS 关于iphone6 和 iphone6 plus 的适配
http://www.ui.cn/detail/26980.html 根据上面说的,iphone6 plus的屏幕的编程时的宽度应该是414,我理解的也是这样,但是我用iphone6 plus 模拟器 ...
- 配置ubuntu虚拟机备忘
#1配置minicom sudo minicom -s sudo minicom -w #1.配置网络,嵌入机的ip地址 ifconfig eth0 10.5.52.202 #2.挂载文件,把虚拟主机 ...