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('"')
}
}