go json.Marshalグループ関数の説明

13505 ワード

go標準ライブラリ(ソースバージョンgo 1.9)は、メタデータを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
"
, 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
}

新タイプEncoer(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('"')
    }
}