https://github.com/mailru/easyjson另辟蹊径,它采用代码生成的方式,为每一个结构体生成对应的json序列化和反序列化方法,类似proto buf,由于是在编译时的代码生成,避免了运行时的内存分配和反射,所以效率比官方的json库快4到5倍。但是它丧失了灵活性,不支持未知类型的json的序列化和反序列化。下面我们来分析下它的源码。
首先配置环境,除了需要下载依赖的包外还需要下载代码生成工具
代码语言:javascript复制go get github.com/mailru/easyjson && go install github.com/mailru/easyjson/...@latest
然后运行命令就可以生成结构体定制的序列化和反序列化方法,不过需要注意的是它不支持main 这个package里面的结构体代码的生成
代码语言:javascript复制easyjson -all <file>.go
下面我们使用一个例子来生成代码:
代码语言:javascript复制package model
import _ "github.com/mailru/easyjson/gen"
type Model struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
ObjectField struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
} `json:"object_field"`
ArrayField []struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
} `json:"array_field"`
}
然后我们运行命令:
代码语言:javascript复制 easyjson -all ./json/easyjson/model/struct.go
可以看到,它生成了代码:json/easyjson/model/struct_easyjson.go
代码语言:javascript复制// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package model
import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)
func easyjson9f2eff5fDecodeLearnJsonEasyjsonModel(in *jlexer.Lexer, out *Model) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "string_field":
out.StringField = string(in.String())
case "int_field":
out.IntField = int(in.Int())
case "object_field":
easyjson9f2eff5fDecode(in, &out.ObjectField)
case "array_field":
if in.IsNull() {
in.Skip()
out.ArrayField = nil
} else {
in.Delim('[')
if out.ArrayField == nil {
if !in.IsDelim(']') {
out.ArrayField = make([]struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}, 0, 2)
} else {
out.ArrayField = []struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}{}
}
} else {
out.ArrayField = (out.ArrayField)[:0]
}
for !in.IsDelim(']') {
var v1 struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}
easyjson9f2eff5fDecode(in, &v1)
out.ArrayField = append(out.ArrayField, v1)
in.WantComma()
}
in.Delim(']')
}
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjson9f2eff5fEncodeLearnJsonEasyjsonModel(out *jwriter.Writer, in Model) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ","string_field":"
out.RawString(prefix[1:])
out.String(string(in.StringField))
}
{
const prefix string = ","int_field":"
out.RawString(prefix)
out.Int(int(in.IntField))
}
{
const prefix string = ","object_field":"
out.RawString(prefix)
easyjson9f2eff5fEncode(out, in.ObjectField)
}
{
const prefix string = ","array_field":"
out.RawString(prefix)
if in.ArrayField == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null")
} else {
out.RawByte('[')
for v2, v3 := range in.ArrayField {
if v2 > 0 {
out.RawByte(',')
}
easyjson9f2eff5fEncode(out, v3)
}
out.RawByte(']')
}
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v Model) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson9f2eff5fEncodeLearnJsonEasyjsonModel(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v Model) MarshalEasyJSON(w *jwriter.Writer) {
easyjson9f2eff5fEncodeLearnJsonEasyjsonModel(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *Model) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson9f2eff5fDecodeLearnJsonEasyjsonModel(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *Model) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson9f2eff5fDecodeLearnJsonEasyjsonModel(l, v)
}
func easyjson9f2eff5fDecode(in *jlexer.Lexer, out *struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "string_field":
out.StringField = string(in.String())
case "int_field":
out.IntField = int(in.Int())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjson9f2eff5fEncode(out *jwriter.Writer, in struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ","string_field":"
out.RawString(prefix[1:])
out.String(string(in.StringField))
}
{
const prefix string = ","int_field":"
out.RawString(prefix)
out.Int(int(in.IntField))
}
out.RawByte('}')
}
里面实现了两个函数:
代码语言:javascript复制func (v Model) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson9f2eff5fEncodeLearnJsonEasyjsonModel(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
代码语言:javascript复制func (v *Model) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson9f2eff5fDecodeLearnJsonEasyjsonModel(&r, v)
return r.Error()
}
它们内部调用的函数,就是生成的定制化的序列化方法和反序列化方法。进一步我们可以看到,序列户方法就是依次取结构体的各个字段,然后拼接json字符串。
代码语言:javascript复制func easyjson9f2eff5fEncodeLearnJsonEasyjsonModel(out *jwriter.Writer, in Model) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ","string_field":"
out.RawString(prefix[1:])
out.String(string(in.StringField))
}
反序列化方式类似,通过lexer解析json数据,然后遍历json抽象语法树,根据jsonkey名字,给结构体对应的字段赋值:
代码语言:javascript复制func easyjson9f2eff5fDecodeLearnJsonEasyjsonModel(in *jlexer.Lexer, out *Model) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "string_field":
out.StringField = string(in.String())
case "int_field":
out.IntField = int(in.Int())
case "object_field":
easyjson9f2eff5fDecode(in, &out.ObjectField)
我们如何使用这些序列化和反序列化方法呢?
代码语言:javascript复制package main
import (
"fmt"
"learn/json/easyjson/model"
"github.com/mailru/easyjson"
)
func main() {
someStruct := &model.Model{StringField: "12", IntField: 12, ObjectField: struct {
StringField string `json:"string_field"`
IntField int `json:"int_field"`
}{}}
rawBytes, err := easyjson.Marshal(someStruct)
fmt.Println(string(rawBytes), err)
someStruct1 := &model.Model{}
err = easyjson.Unmarshal(rawBytes, someStruct1)
fmt.Println(err)
}
我们可以进一步跟进 easyjson.Marshal和 easyjson.Unmarshal 源码位于github.com/mailru/easyjson@v0.7.7/helpers.go
代码语言:javascript复制func Marshal(v Marshaler) ([]byte, error) {
if isNilInterface(v) {
return nullBytes, nil
}
w := jwriter.Writer{}
v.MarshalEasyJSON(&w)
return w.BuildBytes()
}
代码语言:javascript复制func Unmarshal(data []byte, v Unmarshaler) error {
l := jlexer.Lexer{Data: data}
v.UnmarshalEasyJSON(&l)
return l.Error()
}
可以看到,它仅仅是个封装,使得序列化和反序列化方法和官方方法一样。内部调用了传入go对象的 MarshalEasyJSON和UnmarshalEasyJSON 方法。
至此,easyjson的基本原理和使用已经介绍完毕,下一讲,我们分析下easyjson的代码生成的源码。