首先上代码:

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 指南,只包括作者认为最常见的使用方式。抗议无效。

最新文章

  1. Velocity初探小结--velocity使用语法详解
  2. WPF界面布局——Canvas
  3. leetcode 172
  4. [Android] 如何查看apk需要支持的Android版本
  5. gcc链接参数--whole-archive的作用
  6. oracle merge用法
  7. OSI参考模型 VS TCP/IP参考模
  8. 解决ListView异步加载图片错乱问题 .
  9. Java中如何判断当前环境是大端字节顺序还是小端字节顺序
  10. Python学习入门基础教程(learning Python)--3.3.1 Python下的布尔表达式
  11. git命令实战之血泪记录
  12. SQL Server 查询性能优化——创建索引原则(二)
  13. lodash 实现一些常见的功能
  14. Git更改用户名与回退操作
  15. linux使用framebuffer的代码
  16. 用例该如何书写?完整示例-QQ登录界面
  17. [Deep-Learning-with-Python]神经网络入手学习[上]
  18. Django自定义模板函数
  19. Android程序员学WEB前端(4)-HTML(4)-注册页面-Sublime
  20. C++的extern关键字

热门文章

  1. Struts2中的OGNL通配符
  2. 使用jar命令打war包
  3. ndk学习13: proc
  4. 【MavenWeb】初探:创建一个Maven Web项目
  5. 【leetcode】First Missing Positive
  6. <转>VPN技术原理
  7. vps mysql自动关闭
  8. 微信video标签全屏无法退出bug 本文系转载
  9. HTML 基础
  10. NIS域配置详解