go json.Marshal 編組函數講解

go標準庫(源碼版本go1.9)提供了一個將JSON的過程叫編組(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"]}]

可見經過編組之後,如果是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
}
//編碼格式化
type encOpts struct {
    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

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 {
    if t.Implements(marshalerType) {
        return marshalerEncoder
    }
    if t.Kind() != reflect.Ptr && allowAddr {
        if reflect.PtrTo(t).Implements(marshalerType) {
            return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
        }
    }

    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('"')
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章