go json.Marshal 编组函数讲解

go标准库(源码版本go1.9)提供了一个将元数据编组(marshaling)成slice函数,编组通过调用json.Marshal()函数完成:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    type Movie struct {
        Title  string
        Year   int  `json:"released"`
        Color  bool `json:"color,omitempty"`
        Actors []string
    }

    var movies = []Movie{
        {Title: "Casablanca", Year: 1942, Color: false,
            Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
        {Title: "Cool Hand Luke", Year: 1967, Color: true,
            Actors: []string{"Paul Newman"}},
        {Title: "Bullitt", Year: 1968, Color: true,
            Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
    }
    data, err := json.Marshal(movies)
    if err != nil {
        log.Fatalf("JSON marshaling failed: %s", err)
    }
    fmt.Printf("%s\n", data)
}

运行结果:

[{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingrid Bergman"]},{"Title":"Cool Hand Luke","released":1967,"color":true,"Actors":["Paul Newman"]},{"Title":"Bullitt","released":1968,"color":true,"Actors":["Steve McQueen","Jacqueline Bisset"]}]

注意,编码过程默认使用struct的字段名做为JSON的对象(通过reflect技术),只有导出的字段才会被编码,这也是我们为什么使用大写字母开头的字段;另外我们看见经过编组之后,如果是slice 加入了”[“和”]” 符号、string 加入了“” 符号……
那我们看看这个函数是咋处理的:

func Marshal(v interface{}) ([]byte, error) {
    //存储v的编组之后的bytes.Buffer对象(见下 具体数据结构)
    e := &encodeState{}
    //调用编组对象的marshal方法,encOpts 对象:编码过程的配置
    err := e.marshal(v, encOpts{escapeHTML: true})
    if err != nil {
        return nil, err
    }
    return e.Bytes(), nil
}
//编码格式化:默认escapeHtml为true,会转义 <、>、& 符号,如果不想转义,可以自定Encoder对象:  bf := bytes.NewBuffer([]byte{});jsonEncoder := json.NewEncoder(bf);jsonEncoder.SetEscapeHTML(false);jsonEncoder.Encode(interface{})
type encOpts struct {
    //如果为true:int float编码之后会加上“” 引号;默认是false
    quoted bool
    escapeHTML bool
}
//存储v的编组之后的bytes.Buffer对象
type encodeState struct {
    bytes.Buffer // accumulated output
    scratch      [64]byte
}

继续调用encodeState的marshal方法

func (e *encodeState) marshal(v interface{}, opts encOpts) (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)
        }
    }()
    //继续调用relectValue方法
    e.reflectValue(reflect.ValueOf(v), opts)
    return nil
}

reflectValue 函数

func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
   //调用valueEncoder函数生成 encoderFunc 然后执行(e,v,opts)
    valueEncoder(v)(e, v, opts)
}

生成valueEncoder

func valueEncoder(v reflect.Value) encoderFunc {
//判断reflect.value对象是否为一个值
    if !v.IsValid() {
        return invalidValueEncoder
    }
    //继续调用typeEncoder函数
    return typeEncoder(v.Type())
}

typeEncoder:试着去缓存里找该类型的encoder处理函数,以此提高性能,找不到就新建

func typeEncoder(t reflect.Type) encoderFunc {
//encoderCache 是个sync.Map 缓存处理的encoderFunc函数,如果能找到,直接使用
    if fi, ok := encoderCache.Load(t); ok {
        return fi.(encoderFunc)
    }
    var (
        wg sync.WaitGroup
        f  encoderFunc
    )
    wg.Add(1)
    fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) {
        wg.Wait()
        f(e, v, opts)
    }))
    if loaded {
        return fi.(encoderFunc)
    }
    //Cache对象里没有,则自己创建
    f = newTypeEncoder(t, true)
    wg.Done()
    //将创建好的 encoderFunc 对象以type:encoderFunc 的形式存入缓存map中
    encoderCache.Store(t, f)
    return f
}

newTypeEncoer(reflect.Type,bool)函数:该函数作用根据反射,确定类型函数,进而进行编码

func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
    //检查该类型是否有自定的MarshalJSON() ([]byte, error)函数,如果有直接使用
    if t.Implements(marshalerType) {
        return marshalerEncoder
    }
    if t.Kind() != reflect.Ptr && allowAddr {
        if reflect.PtrTo(t).Implements(marshalerType) {
            return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
        }
    }
    //检查是否有自定义MarshalText() (text []byte, err error) 函数
    if t.Implements(textMarshalerType) {
        return textMarshalerEncoder
    }
    if t.Kind() != reflect.Ptr && allowAddr {
        if reflect.PtrTo(t).Implements(textMarshalerType) {
            return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
        }
    }

    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
    }
}

拿其中一个函数示例:intEncoder

func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {
//转成[]byte
    b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
    if opts.quoted {
        e.WriteByte('"')
    }
    //写入bytes.Buffer对象里
    e.Write(b)
    if opts.quoted {
        e.WriteByte('"')
    }
}

你可能感兴趣的:(go json.Marshal 编组函数讲解)