前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang源码分析:json-iterator/go(2)

golang源码分析:json-iterator/go(2)

作者头像
golangLeetcode
发布2023-09-06 19:18:43
3510
发布2023-09-06 19:18:43
举报
文章被收录于专栏:golang算法架构leetcode技术php

接着分析json-iterator的源码,首先从序列化函数入手

代码语言:javascript
复制
b, err := jsoniter.Marshal(group)

它的定义位于github.com/json-iterator/go@v1.1.12/adapter.go

代码语言:javascript
复制
func Marshal(v interface{}) ([]byte, error) {
  return ConfigDefault.Marshal(v)
}

其中ConfigDefault是一个全局变量:github.com/json-iterator/go@v1.1.12/config.go

代码语言:javascript
复制
var ConfigDefault = Config{
  EscapeHTML: true,
}.Froze()

其中定义了各种pool和cache提供缓存能力来提升性能:

代码语言:javascript
复制
func (cfg Config) Froze() API {
  api := &frozenConfig{
  api.streamPool = &sync.Pool{
  api.iteratorPool = &sync.Pool{
  cfg.decoderCache = concurrent.NewMap()
  cfg.encoderCache = concurrent.NewMap()
  encoderExtension := EncoderExtension{}
  decoderExtension := DecoderExtension{}

接口我们看下它的序列化函数,它调用了WriteVal

代码语言:javascript
复制
func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
        stream := cfg.BorrowStream(nil)
        stream.WriteVal(v)
        result := stream.Buffer()

github.com/json-iterator/go@v1.1.12/reflect.go,它通过反射获取类型,然后通过类型找到对应的编码函数,最后通过Encode方法进行编码,查找过程中优先从cache里获取:

代码语言:javascript
复制
func (stream *Stream) WriteVal(val interface{}) {
    cacheKey := reflect2.RTypeOf(val)
    encoder := stream.cfg.getEncoderFromCache(cacheKey)
    typ := reflect2.TypeOf(val)
    encoder = stream.cfg.EncoderOf(typ)
    encoder.Encode(reflect2.PtrOf(val), stream)  
代码语言:javascript
复制
func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder {
  cacheKey := typ.RType()
  encoder = encoderOfType(ctx, typ)
  if typ.LikePtr() {
    encoder = &onePtrEncoder{encoder}
  }
代码语言:javascript
复制
func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
        encoder := getTypeEncoderFromExtension(ctx, typ)
        encoder = createEncoderOfType(ctx, typ)

如果没有找到,就创建一个

代码语言:javascript
复制
func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
        placeholder := &placeholderEncoder{}
        ctx.encoders[typ] = placeholder
        encoder = _createEncoderOfType(ctx, typ)     
        placeholder.encoder = encoder

可以看到,它优先根据类型,获取RawMessahge,JsonNumber,Marshaler,Any,Native几种类型的编码函数,获取不到,根据Kind,获取基本类型的编码函数:

代码语言:javascript
复制
func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
encoder := createEncoderOfJsonRawMessage(ctx, typ)
encoder = createEncoderOfJsonNumber(ctx, typ)
encoder = createEncoderOfMarshaler(ctx, typ)
encoder = createEncoderOfAny(ctx, typ)
encoder = createEncoderOfNative(ctx, typ)
kind := typ.Kind()
switch kind {
  case reflect.Interface:
    return &dynamicEncoder{typ}
  case reflect.Struct:
    return encoderOfStruct(ctx, typ)
  case reflect.Array:
    return encoderOfArray(ctx, typ)
  case reflect.Slice:
    return encoderOfSlice(ctx, typ)
  case reflect.Map:
    return encoderOfMap(ctx, typ)
  case reflect.Ptr:
    return encoderOfOptional(ctx, typ)
  default:
    return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())}
  }

如果是Interface类型,它使用dynamicEncoder,定义位于:github.com/json-iterator/go@v1.1.12/reflect_dynamic.go

代码语言:javascript
复制
type dynamicEncoder struct {
  valType reflect2.Type
}  
代码语言:javascript
复制
func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
  obj := encoder.valType.UnsafeIndirect(ptr)
  stream.WriteVal(obj)
}

struct类型的encoder定义位于:

github.com/json-iterator/go@v1.1.12/reflect_struct_encoder.go

代码语言:javascript
复制
func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
      structDescriptor := describeStruct(ctx, typ)
      for _, binding := range structDescriptor.Fields {
      for _, toName := range binding.ToNames {
      for _, old := range orderedBindings {

它先获取结构体类型的描述信息,然后通过遍历描述信息的字段,以及绑定的名称,最后进行每个字段的递归处理。

json数字的处理定义位于:github.com/json-iterator/go@v1.1.12/reflect_json_number.go,里面有两个分支,分布对应json的Number和jsoniter的Number类型。

代码语言:javascript
复制
func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder {
  if typ.AssignableTo(jsonNumberType) {
    return &jsonNumberCodec{}
  }
  if typ.AssignableTo(jsoniterNumberType) {
    return &jsoniterNumberCodec{}
  }
  return nil
}

他俩都是通过反射获取的对象的类型信息:

代码语言:javascript
复制
var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem()
var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem()

对应的,解码函数定义如下:

代码语言:javascript
复制
type jsonNumberCodec struct {
}
代码语言:javascript
复制
func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 switch iter.WhatIsNext() {
  case StringValue:
    *((*Number)(ptr)) = Number(iter.ReadString())
  case NilValue:
    iter.skipFourBytes('n', 'u', 'l', 'l')
    *((*Number)(ptr)) = ""
  default:
    *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
  }

字符串原位赋值,不解析,所以没有内存分配和释放,速度很快,不错的想法。指针指向json中的位置。编码函数其实就是简单地将函数转换成字符串。

代码语言:javascript
复制
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
   stream.WriteRaw(string(number))  
代码语言:javascript
复制
type Number string
        // String returns the literal text of the number.
func (n Number) String() string { return string(n) }
代码语言:javascript
复制
// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
  return strconv.ParseFloat(string(n), 64)
}
代码语言:javascript
复制
// Int64 returns the number as an int64.
func (n Number) Int64() (int64, error) {
  return strconv.ParseInt(string(n), 10, 64)
}

类似的浮点数处理也一样,先按照字符串读取,这样可以避免内存分配,然后按需解析:github.com/json-iterator/go@v1.1.12/iter_float.go

代码语言:javascript
复制
func (iter *Iterator) readNumberAsString() (ret string) {
   for {
    for i := iter.head; i < iter.tail; i++ {
      c := iter.buf[i]
      switch c {
      case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
        str = append(str, c)

类型的解析,会通过map来缓存类型和对应解析函数的关联关系:github.com/json-iterator/go@v1.1.12/reflect_extension.go

代码语言:javascript
复制
type EncoderExtension map[reflect2.Type]ValEncoder
type DecoderExtension map[reflect2.Type]ValDecoder

对于结构体来说,describeStruct通过反射获取类型,然后解析出其描述信息,对于它的每个field可以进行递归处理:

代码语言:javascript
复制
func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
  structType := typ.(*reflect2.UnsafeStructType)
  for i := 0; i < structType.NumField(); i++ {
    if field.Type().Kind() == reflect.Struct {
        structDescriptor := describeStruct(ctx, field.Type())
        for _, binding := range structDescriptor.Fields {
          binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty}
          binding.Decoder = &structFieldDecoder{field, binding.Decoder}
return createStructDescriptor(ctx, typ, bindings, embeddedBindings)

最后创建 StructDescriptor,的实例:

代码语言:javascript
复制
func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
  for _, extension := range extensions {
    extension.UpdateStructDescriptor(structDescriptor)

其中用到的反射并不是golang原生的反射,而是新封装的:

github.com/modern-go/reflect2@v1.0.2/reflect2.go,它实现了如下接口:

代码语言:javascript
复制
type Type interface {
  Kind() reflect.Kind
  // New return pointer to data of this type
  New() interface{}
  // UnsafeNew return the allocated space pointed by unsafe.Pointer
  UnsafeNew() unsafe.Pointer
  // PackEFace cast a unsafe pointer to object represented pointer
  PackEFace(ptr unsafe.Pointer) interface{}
  // Indirect dereference object represented pointer to this type
  Indirect(obj interface{}) interface{}
  // UnsafeIndirect dereference pointer to this type
  UnsafeIndirect(ptr unsafe.Pointer) interface{}
  // Type1 returns reflect.Type
  Type1() reflect.Type
  Implements(thatType Type) bool
  String() string
  RType() uintptr
  // interface{} of this type has pointer like behavior
  LikePtr() bool
  IsNullable() bool
  IsNil(obj interface{}) bool
  UnsafeIsNil(ptr unsafe.Pointer) bool
  Set(obj interface{}, val interface{})
  UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
  AssignableTo(anotherType Type) bool
}

介绍完序列化函数,我们来分析下反序列化函数:

代码语言:javascript
复制
json.Unmarshal(b, &data)

它的入口位于:github.com/json-iterator/go@v1.1.12/config.go,调用了迭代器的ReadVal函数:

代码语言:javascript
复制
func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
  iter.ReadVal(v)
  c := iter.nextToken()

具体定义位于:github.com/json-iterator/go@v1.1.12/reflect.go,先从cache获取decoder,获取失败,通过反射获取类型信息,然后通过类型获取decoder,最后调用decoder的Decode方法来进行json解析:

代码语言:javascript
复制
func (iter *Iterator) ReadVal(obj interface{}) {
  cacheKey := reflect2.RTypeOf(obj)
  decoder := iter.cfg.getDecoderFromCache(cacheKey)
  typ := reflect2.TypeOf(obj)
  decoder = iter.cfg.DecoderOf(typ)
  ptr := reflect2.PtrOf(obj)
  decoder.Decode(ptr, iter)
代码语言:javascript
复制
func (cfg *frozenConfig) DecoderOf(typ reflect2.Type) ValDecoder {
 ctx := &ctx{
    frozenConfig: cfg,
    prefix:       "",
    decoders:     map[reflect2.Type]ValDecoder{},
    encoders:     map[reflect2.Type]ValEncoder{},
  }
    ptrType := typ.(*reflect2.UnsafePtrType)
    decoder = decoderOfType(ctx, ptrType.Elem())

如果缓存拿不到,就创建这种类型的decoder:

代码语言:javascript
复制
func decoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder {
    decoder := getTypeDecoderFromExtension(ctx, typ)
    decoder = createDecoderOfType(ctx, typ)
    decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder)

和获取编码函数的方式类似:

代码语言:javascript
复制
func createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder {
  placeholder := &placeholderDecoder{}
  ctx.decoders[typ] = placeholder
  decoder = _createDecoderOfType(ctx, typ)
  placeholder.decoder = decoder

自定义类型的解码器如果没有找到,就根据Kind,获取基本类型的解码器:

代码语言:javascript
复制
func _createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder {
decoder := createDecoderOfJsonRawMessage(ctx, typ)
decoder = createDecoderOfJsonNumber(ctx, typ)
decoder = createDecoderOfMarshaler(ctx, typ)
decoder = createDecoderOfAny(ctx, typ)
decoder = createDecoderOfNative(ctx, typ)
switch typ.Kind() {
  case reflect.Interface:
    ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType)
    if isIFace {
      return &ifaceDecoder{valType: ifaceType}
    }
    return &efaceDecoder{}
  case reflect.Struct:
    return decoderOfStruct(ctx, typ)
  case reflect.Array:
    return decoderOfArray(ctx, typ)
  case reflect.Slice:
    return decoderOfSlice(ctx, typ)
  case reflect.Map:
    return decoderOfMap(ctx, typ)
  case reflect.Ptr:
    return decoderOfOptional(ctx, typ)
  default:
    return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())}
  }
}

获取类型的过程,的TypeOf是通过指针直接获取的:github.com/modern-go/reflect2@v1.0.2/reflect2.go

代码语言:javascript
复制
func RTypeOf(obj interface{}) uintptr {
  return uintptr(unpackEFace(obj).rtype)
}
代码语言:javascript
复制
func TypeOf(obj interface{}) Type {
  return ConfigUnsafe.TypeOf(obj)
}  
代码语言:javascript
复制
func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
  cacheKey := uintptr(unpackEFace(obj).rtype)
  typeObj, found := cfg.cache.Load(cacheKey)
  if found {
    return typeObj.(Type)
  }
  return cfg.Type2(reflect.TypeOf(obj))
}  
代码语言:javascript
复制
func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
   type2 := cfg.wrapType(type1
代码语言:javascript
复制
func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
 safeType := safeType{Type: type1, cfg: cfg}
 switch type1.Kind() {
  case reflect.Struct:
    if cfg.useSafeImplementation {
      return &safeStructType{safeType}
    }
    return newUnsafeStructType(cfg, type1)
  case reflect.Array:
    if cfg.useSafeImplementation {
      return &safeSliceType{safeType}
    }
    return newUnsafeArrayType(cfg, type1)
  case reflect.Slice:
    if cfg.useSafeImplementation {
      return &safeSliceType{safeType}
    }
    return newUnsafeSliceType(cfg, type1)
  case reflect.Map:
    if cfg.useSafeImplementation {
      return &safeMapType{safeType}
    }
    return newUnsafeMapType(cfg, type1)
  case reflect.Ptr, reflect.Chan, reflect.Func:
    if cfg.useSafeImplementation {
      return &safeMapType{safeType}
    }
    return newUnsafePtrType(cfg, type1)
  case reflect.Interface:
    if cfg.useSafeImplementation {
      return &safeMapType{safeType}
    }
    if type1.NumMethod() == 0 {
      return newUnsafeEFaceType(cfg, type1)
    }
    return newUnsafeIFaceType(cfg, type1)
  default:
    if cfg.useSafeImplementation {
      return &safeType
    }
    return newUnsafeType(cfg, type1)
  }
}

github.com/modern-go/reflect2@v1.0.2/unsafe_eface.go

代码语言:javascript
复制
func unpackEFace(obj interface{}) *eface {
  return (*eface)(unsafe.Pointer(&obj))
}

获取类型的解码函数后,我们就可以通过iter迭代器来沿着json字符串进行解析了:github.com/json-iterator/go@v1.1.12/iter.go,比如nextToken用于过滤空格

代码语言:javascript
复制
func (iter *Iterator) nextToken() byte {
          // a variation of skip whitespaces, returning the next non-whitespace token
  for {
    for i := iter.head; i < iter.tail; i++ {
      c := iter.buf[i]
      switch c {
      case ' ', '\n', '\t', '\r':
      continue

下面详细介绍下结构体的解码器是如何定义的:github.com/json-iterator/go@v1.1.12/reflect_struct_decoder.go,先获取结构体的描述信息,然后根据描述信息里的Fieds,递归获取解码器,然后通过map缓存,方便后面获取:

代码语言:javascript
复制
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
  structDescriptor := describeStruct(ctx, typ)
  for _, binding := range structDescriptor.Fields {
    for _, fromName := range binding.FromNames {
        ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding)
        fields := map[string]*structFieldDecoder{}
          for k, binding := range bindings {
            fields[k] = binding.Decoder.(*structFieldDecoder)
          }
return createStructDecoder(ctx, typ, fields)

注意这里有个优化,在字段少于10个的结构体,直接在内存定义字段key的hash值和对应的解码函数,匹配的时候可以通过hash值匹配,然后找到解码函数,不用走map的申请和匹配,提升速度。超过10个则退化到map查找:

代码语言:javascript
复制
func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder {
  switch len(fields) {
    case 0:
    for fieldName, fieldDecoder := range fields {
      fieldHash := calcHash(fieldName, ctx.caseSensitive())
      _, known := knownHash[fieldHash]
      if known {
        return &generalStructDecoder{typ, fields, false}
      }
      knownHash[fieldHash] = struct{}{}
      return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}
    }
   case 10:  
代码语言:javascript
复制
type generalStructDecoder struct {
  typ                   reflect2.Type
  fields                map[string]*structFieldDecoder
  disallowUnknownFields bool
}
代码语言:javascript
复制
type structFieldDecoder struct {
  field        reflect2.StructField
  fieldDecoder ValDecoder
}

decoder的定义是个递归的过程:

代码语言:javascript
复制
func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
        fieldPtr := decoder.field.UnsafeGet(ptr)
        decoder.fieldDecoder.Decode(fieldPtr, iter)

值的解码定义位于:github.com/json-iterator/go@v1.1.12/reflect.go

代码语言:javascript
复制
type ValDecoder interface {
  Decode(ptr unsafe.Pointer, iter *Iterator)
}
代码语言:javascript
复制
// ValDecoder is an internal type registered to cache as needed.
// Don't confuse jsoniter.ValDecoder with json.Decoder.
// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link).
//
// Reflection on type to create decoders, which is then cached
// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions
// 1. create instance of new value, for example *int will need a int to be allocated
// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New
// 3. assignment to map, both key and value will be reflect.Value
// For a simple struct binding, it will be reflect.Value free and allocation free

native类型的解码器定义位于:github.com/json-iterator/go@v1.1.12/reflect_native.go,可以看到,对于每一种基础类型,都定义了对应的解码器:

代码语言:javascript
复制
func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder {
 if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 {
    sliceDecoder := decoderOfSlice(ctx, typ)
    return &base64Codec{sliceDecoder: sliceDecoder}
  }
  typeName := typ.String()
  switch typ.Kind() {
  case reflect.String:
    if typeName != "string" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem())
    }
    return &stringCodec{}
  case reflect.Int:
    if typeName != "int" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem())
    }
    if strconv.IntSize == 32 {
      return &int32Codec{}
    }
    return &int64Codec{}
  case reflect.Int8:
    if typeName != "int8" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem())
    }
    return &int8Codec{}
  case reflect.Int16:
    if typeName != "int16" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem())
    }
    return &int16Codec{}
  case reflect.Int32:
    if typeName != "int32" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem())
    }
    return &int32Codec{}
  case reflect.Int64:
    if typeName != "int64" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem())
    }
    return &int64Codec{}
  case reflect.Uint:
    if typeName != "uint" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem())
    }
    if strconv.IntSize == 32 {
      return &uint32Codec{}
    }
    return &uint64Codec{}
  case reflect.Uint8:
    if typeName != "uint8" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem())
    }
    return &uint8Codec{}
  case reflect.Uint16:
    if typeName != "uint16" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem())
    }
    return &uint16Codec{}
  case reflect.Uint32:
    if typeName != "uint32" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem())
    }
    return &uint32Codec{}
  case reflect.Uintptr:
    if typeName != "uintptr" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem())
    }
    if ptrSize == 32 {
      return &uint32Codec{}
    }
    return &uint64Codec{}
  case reflect.Uint64:
    if typeName != "uint64" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem())
    }
    return &uint64Codec{}
  case reflect.Float32:
    if typeName != "float32" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem())
    }
    return &float32Codec{}
  case reflect.Float64:
    if typeName != "float64" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem())
    }
    return &float64Codec{}
  case reflect.Bool:
    if typeName != "bool" {
      return decoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem())
    }
    return &boolCodec{}
  }
  return nil
}
      
代码语言:javascript
复制
type boolCodec struct {
}
代码语言:javascript
复制
func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
  if !iter.ReadNil() {
    *((*bool)(ptr)) = iter.ReadBool()
  }
}

bool解码器,本质上就是把json字符串中的true,false解析成bool值:

代码语言:javascript
复制
func (iter *Iterator) ReadBool() (ret bool) {
  c := iter.nextToken()
  if c == 't' {
    iter.skipThreeBytes('r', 'u', 'e')
    return true
  }
  if c == 'f' {
    iter.skipFourBytes('a', 'l', 's', 'e')
    return false
  }
  iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c}))
  return
}

类似浮点数:

代码语言:javascript
复制
  type float32Codec struct {
}
代码语言:javascript
复制
func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
  if !iter.ReadNil() {
    *((*float32)(ptr)) = iter.ReadFloat32()
  }
}
代码语言:javascript
复制
func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
  stream.WriteFloat32(*((*float32)(ptr)))
}  
代码语言:javascript
复制
//ReadFloat32 read float32
func (iter *Iterator) ReadFloat32() (ret float32) {
  c := iter.nextToken()
  if c == '-' {
    return -iter.readPositiveFloat32()
  }
  iter.unreadByte()
  return iter.readPositiveFloat32()
}

浮点数的解析过程中,直接通过字符的值,最后计算出浮点数的值:

代码语言:javascript
复制
func (iter *Iterator) readPositiveFloat32() (ret float32) {
  i := iter.head
  // first char
  if i == iter.tail {
    return iter.readFloat32SlowPath()
  }
  c := iter.buf[i]
  i++
  ind := floatDigits[c]
  switch ind {
  case invalidCharForNumber:
    return iter.readFloat32SlowPath()
  case endOfNumber:
    iter.ReportError("readFloat32", "empty number")
    return
  case dotInNumber:
    iter.ReportError("readFloat32", "leading dot is invalid")
    return
  case 0:
    if i == iter.tail {
      return iter.readFloat32SlowPath()
    }
    c = iter.buf[i]
    switch c {
    case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
      iter.ReportError("readFloat32", "leading zero is invalid")
      return
    }
  }
  value := uint64(ind)
  // chars before dot
non_decimal_loop:
  for ; i < iter.tail; i++ {
    c = iter.buf[i]
    ind := floatDigits[c]
    switch ind {
    case invalidCharForNumber:
      return iter.readFloat32SlowPath()
    case endOfNumber:
      iter.head = i
      return float32(value)
    case dotInNumber:
      break non_decimal_loop
    }
    if value > uint64SafeToMultiple10 {
      return iter.readFloat32SlowPath()
    }
    value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
  }
  // chars after dot
  if c == '.' {
    i++
    decimalPlaces := 0
    if i == iter.tail {
      return iter.readFloat32SlowPath()
    }
    for ; i < iter.tail; i++ {
      c = iter.buf[i]
      ind := floatDigits[c]
      switch ind {
      case endOfNumber:
        if decimalPlaces > 0 && decimalPlaces < len(pow10) {
          iter.head = i
          return float32(float64(value) / float64(pow10[decimalPlaces]))
        }
        // too many decimal places
        return iter.readFloat32SlowPath()
      case invalidCharForNumber, dotInNumber:
        return iter.readFloat32SlowPath()
      }
      decimalPlaces++
      if value > uint64SafeToMultiple10 {
        return iter.readFloat32SlowPath()
      }
      value = (value << 3) + (value << 1) + uint64(ind)
    }
  }
  return iter.readFloat32SlowPath()
}

github.com/json-iterator/go@v1.1.12/reflect_extension.go结构体的描述信息是通过反射,获取结构体的字段信息,最后组建的:

代码语言:javascript
复制
func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
for i := 0; i < structType.NumField(); i++ {
  field := structType.Field(i)
  tag, hastag := field.Tag().Lookup(ctx.getTagKey())
  fieldNames := calcFieldNames(field.Name(), tagParts[0], tag)
  decoder = decoderOfType(ctx.append(field.Name()), field.Type())
      binding := &Binding{
      Field:     field,
      FromNames: fieldNames,
      ToNames:   fieldNames,
      Decoder:   decoder,
      Encoder:   encoder,
    }
return createStructDescriptor(ctx, typ, bindings, embeddedBindings)

json迭代器的定义位于github.com/json-iterator/go@v1.1.12/iter.go

代码语言:javascript
复制
type Iterator struct {
  cfg              *frozenConfig
  reader           io.Reader
  buf              []byte
  head             int
  tail             int
  depth            int
  captureStartedAt int
  captured         []byte
  Error            error
  Attachment       interface{} // open for customized decoder
}

read函数不断向后读取字符,并根据获得的key,找到val对应的类型和对应的解析函数,最后调用解析函数,完成解析和绑定:

代码语言:javascript
复制
func (iter *Iterator) Read() interface{} {
  valueType := iter.WhatIsNext()
  switch valueType {
  case StringValue:
    return iter.ReadString()
  case NumberValue:

比如结构体的解析位于:

github.com/json-iterator/go@v1.1.12/reflect_struct_decoder.go

代码语言:javascript
复制
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
  for c = ','; c == ','; c = iter.nextToken() {
    decoder.decodeOneField(ptr, iter)
  }
代码语言:javascript
复制
type structFieldDecoder struct {
  field        reflect2.StructField
  fieldDecoder ValDecoder
}  
代码语言:javascript
复制
func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
  fieldPtr := decoder.field.UnsafeGet(ptr)
  decoder.fieldDecoder.Decode(fieldPtr, iter)
  if iter.Error != nil && iter.Error != io.EOF {
    iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error())
  }
}

可以看到每个字段的解析过程

代码语言:javascript
复制
func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) {
   field = iter.ReadString()
    fieldDecoder = decoder.fields[field]
    if fieldDecoder == nil && !iter.cfg.caseSensitive {
      fieldDecoder = decoder.fields[strings.ToLower(field)]
    }
        c := iter.nextToken()
    if c != ':' {
        c := iter.nextToken()
        fieldDecoder.Decode(ptr, iter)

先解析出结构体每个field的标识,存入标识到解析方法的影射的map里,供后面解析使用。解析的时候,解析出json的对象后,根据key string到field里面去查,时间复杂度O(1),得到value的解析函数,如此递归。

代码语言:javascript
复制
type generalStructDecoder struct {
  typ                   reflect2.Type
  fields                map[string]*structFieldDecoder
  disallowUnknownFields bool
}    
代码语言:javascript
复制
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
  for c = ','; c == ','; c = iter.nextToken() {
    decoder.decodeOneField(ptr, iter)
  }
  iter.decrementDepth()
代码语言:javascript
复制
type tenFieldsStructDecoder struct {
  typ            reflect2.Type
  fieldHash1     int64
  fieldDecoder1  *structFieldDecoder
  fieldHash2     int64
  fieldDecoder2  *structFieldDecoder
  fieldHash3     int64
  fieldDecoder3  *structFieldDecoder
  fieldHash4     int64
  fieldDecoder4  *structFieldDecoder
  fieldHash5     int64
  fieldDecoder5  *structFieldDecoder
  fieldHash6     int64
  fieldDecoder6  *structFieldDecoder
  fieldHash7     int64
  fieldDecoder7  *structFieldDecoder
  fieldHash8     int64
  fieldDecoder8  *structFieldDecoder
  fieldHash9     int64
  fieldDecoder9  *structFieldDecoder
  fieldHash10    int64
  fieldDecoder10 *structFieldDecoder
}

小于10个的时候,自己做了hash,避免了,map的寻址,直接进行结构体的字段和hash值匹配,从json里直接计算key的hash,通过内存运算加速。

代码语言:javascript
复制
func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
for {
  switch iter.readFieldHash() {
   case decoder.fieldHash1:
      decoder.fieldDecoder1.Decode(ptr, iter)  
代码语言:javascript
复制
func (iter *Iterator) readFieldHash() int64 {
  for {
    for i := iter.head; i < iter.tail; i++ {
      // require ascii string and no escape
      b := iter.buf[i]
      if b == '\\' {
        iter.head = i
        for _, b := range iter.readStringSlowPath() {
          if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive {
            b += 'a' - 'A'
          }
          hash ^= int64(b)
          hash *= 0x1000193
        }
      return &generalStructDecoder{typ, fields, false}

超过10个字段,使用上面的通用decoder来解码:

代码语言:javascript
复制
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
    for c = ','; c == ','; c = iter.nextToken() {
    decoder.decodeOneField(ptr, iter)
  }

超过10个字段的场景,依次遍历当前json对象内部的所有字段,尝试进行,和go 结构体的每个field进行匹配,field照样是到map里面去取:

代码语言:javascript
复制
func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) {
      fieldDecoder.Decode(ptr, iter)      
代码语言:javascript
复制
func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
        fieldPtr := decoder.field.UnsafeGet(ptr)
        decoder.fieldDecoder.Decode(fieldPtr, iter)  
代码语言:javascript
复制
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
 for k, binding := range bindings {
    fields[k] = binding.Decoder.(*structFieldDecoder)
  }
if !ctx.caseSensitive() {
    for k, binding := range bindings {
      if _, found := fields[strings.ToLower(k)]; !found {
        fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
return createStructDecoder(ctx, typ, fields)

github.com/json-iterator/go@v1.1.12/reflect_extension.go可以看到结构体描述信息是如何组装的:

代码语言:javascript
复制
func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
   bindings := []*Binding{}
   for i := 0; i < structType.NumField(); i++ {
      binding := &Binding{
      Field:     field,
      FromNames: fieldNames,
      ToNames:   fieldNames,
      Decoder:   decoder,
      Encoder:   encoder,
    }
bindings = append(bindings, binding)

组装完成后会对描述信息排序,方便后面加速查找:

代码语言:javascript
复制
func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
  allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...))
  sort.Sort(allBindings)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-03-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档