golang float32转float64精度丢失_聊聊golang的zap的ReflectType

本文详细探讨了Golang zap 日志库中处理反射类型的逻辑,包括sweetenFields、Any、Reflect、AddTo、AddReflected以及json.Encode等关键步骤,展示了zap如何处理非标准类型,并通过具体实例说明了转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要研究一下golang的zap的ReflectType

e39442042f45ead598d7d922b14a6641.png

sweetenFields

zap@v1.16.0/sugar.go

func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {    if len(args) == 0 {        return nil    }    // Allocate enough space for the worst case; if users pass only structured    // fields, we shouldn't penalize them with extra allocations.    fields := make([]Field, 0, len(args))    var invalid invalidPairs    for i := 0; i  0 {        s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))    }    return fields}

sweetenFields方法执行的是fields = append(fields, Any(keyStr, val))

Any

zap@v1.16.0/field.go

func Any(key string, value interface{}) Field {    switch val := value.(type) {    case zapcore.ObjectMarshaler:        return Object(key, val)    case zapcore.ArrayMarshaler:        return Array(key, val)    case bool:        return Bool(key, val)    case *bool:        return Boolp(key, val)    case []bool:        return Bools(key, val)    case complex128:        return Complex128(key, val)    case *complex128:        return Complex128p(key, val)    case []complex128:        return Complex128s(key, val)    case complex64:        return Complex64(key, val)    case *complex64:        return Complex64p(key, val)    case []complex64:        return Complex64s(key, val)    case float64:        return Float64(key, val)    case *float64:        return Float64p(key, val)    case []float64:        return Float64s(key, val)    case float32:        return Float32(key, val)    case *float32:        return Float32p(key, val)    case []float32:        return Float32s(key, val)    case int:        return Int(key, val)    case *int:        return Intp(key, val)    case []int:        return Ints(key, val)    case int64:        return Int64(key, val)    case *int64:        return Int64p(key, val)    case []int64:        return Int64s(key, val)    case int32:        return Int32(key, val)    case *int32:        return Int32p(key, val)    case []int32:        return Int32s(key, val)    case int16:        return Int16(key, val)    case *int16:        return Int16p(key, val)    case []int16:        return Int16s(key, val)    case int8:        return Int8(key, val)    case *int8:        return Int8p(key, val)    case []int8:        return Int8s(key, val)    case string:        return String(key, val)    case *string:        return Stringp(key, val)    case []string:        return Strings(key, val)    case uint:        return Uint(key, val)    case *uint:        return Uintp(key, val)    case []uint:        return Uints(key, val)    case uint64:        return Uint64(key, val)    case *uint64:        return Uint64p(key, val)    case []uint64:        return Uint64s(key, val)    case uint32:        return Uint32(key, val)    case *uint32:        return Uint32p(key, val)    case []uint32:        return Uint32s(key, val)    case uint16:        return Uint16(key, val)    case *uint16:        return Uint16p(key, val)    case []uint16:        return Uint16s(key, val)    case uint8:        return Uint8(key, val)    case *uint8:        return Uint8p(key, val)    case []byte:        return Binary(key, val)    case uintptr:        return Uintptr(key, val)    case *uintptr:        return Uintptrp(key, val)    case []uintptr:        return Uintptrs(key, val)    case time.Time:        return Time(key, val)    case *time.Time:        return Timep(key, val)    case []time.Time:        return Times(key, val)    case time.Duration:        return Duration(key, val)    case *time.Duration:        return Durationp(key, val)    case []time.Duration:        return Durations(key, val)    case error:        return NamedError(key, val)    case []error:        return Errors(key, val)    case fmt.Stringer:        return Stringer(key, val)    default:        return Reflect(key, val)    }}

Any方法会根据value的类型返回不同的Field,如果value没有实现zapcore.ObjectMarshaler、zapcore.ArrayMarshaler,也不是基础类型,则走的是默认的Reflect(key, val)

Reflect

zap@v1.16.0/field.go

func Reflect(key string, val interface{}) Field {    return Field{Key: key, Type: zapcore.ReflectType, Interface: val}}

Reflect创建的Field类型的Type为zapcore.ReflectType

AddTo

zap@v1.16.0/zapcore/field.go

func (f Field) AddTo(enc ObjectEncoder) {    var err error    switch f.Type {    case ArrayMarshalerType:        err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))    case ObjectMarshalerType:        err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))    case BinaryType:        enc.AddBinary(f.Key, f.Interface.([]byte))    case BoolType:        enc.AddBool(f.Key, f.Integer == 1)    case ByteStringType:        enc.AddByteString(f.Key, f.Interface.([]byte))    case Complex128Type:        enc.AddComplex128(f.Key, f.Interface.(complex128))    case Complex64Type:        enc.AddComplex64(f.Key, f.Interface.(complex64))    case DurationType:        enc.AddDuration(f.Key, time.Duration(f.Integer))    case Float64Type:        enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))    case Float32Type:        enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))    case Int64Type:        enc.AddInt64(f.Key, f.Integer)    case Int32Type:        enc.AddInt32(f.Key, int32(f.Integer))    case Int16Type:        enc.AddInt16(f.Key, int16(f.Integer))    case Int8Type:        enc.AddInt8(f.Key, int8(f.Integer))    case StringType:        enc.AddString(f.Key, f.String)    case TimeType:        if f.Interface != nil {            enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))        } else {            // Fall back to UTC if location is nil.            enc.AddTime(f.Key, time.Unix(0, f.Integer))        }    case TimeFullType:        enc.AddTime(f.Key, f.Interface.(time.Time))    case Uint64Type:        enc.AddUint64(f.Key, uint64(f.Integer))    case Uint32Type:        enc.AddUint32(f.Key, uint32(f.Integer))    case Uint16Type:        enc.AddUint16(f.Key, uint16(f.Integer))    case Uint8Type:        enc.AddUint8(f.Key, uint8(f.Integer))    case UintptrType:        enc.AddUintptr(f.Key, uintptr(f.Integer))    case ReflectType:        err = enc.AddReflected(f.Key, f.Interface)    case NamespaceType:        enc.OpenNamespace(f.Key)    case StringerType:        err = encodeStringer(f.Key, f.Interface, enc)    case ErrorType:        encodeError(f.Key, f.Interface.(error), enc)    case SkipType:        break    default:        panic(fmt.Sprintf("unknown field type: %v", f))    }    if err != nil {        enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())    }}

AddTo方法根据Field的类型做不同处理,如果是ReflectType类型,则执行的是enc.AddReflected(f.Key, f.Interface)

AddReflected

zap@v1.16.0/zapcore/json_encoder.go

func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error {    valueBytes, err := enc.encodeReflected(obj)    if err != nil {        return err    }    enc.addKey(key)    _, err = enc.buf.Write(valueBytes)    return err}func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) {    if obj == nil {        return nullLiteralBytes, nil    }    enc.resetReflectBuf()    if err := enc.reflectEnc.Encode(obj); err != nil {        return nil, err    }    enc.reflectBuf.TrimNewline()    return enc.reflectBuf.Bytes(), nil}func (enc *jsonEncoder) resetReflectBuf() {    if enc.reflectBuf == nil {        enc.reflectBuf = bufferpool.Get()        enc.reflectEnc = json.NewEncoder(enc.reflectBuf)        // For consistency with our custom JSON encoder.        enc.reflectEnc.SetEscapeHTML(false)    } else {        enc.reflectBuf.Reset()    }}

jsonEncoder的AddReflected方法用enc.encodeReflected(obj)来序列化value;encodeReflected方法执行的是enc.resetReflectBuf()及enc.reflectEnc.Encode(obj);resetReflectBuf方法在reflectBuf为nil时创建reflectBuf及json.NewEncoder(enc.reflectBuf),不为nil时执行reflectBuf.Reset();enc.reflectEnc用的是golang内置的json encoder

json.Encode

/usr/local/go/src/encoding/json/stream.go

func NewEncoder(w io.Writer) *Encoder {    return &Encoder{w: w, escapeHTML: true}}func (enc *Encoder) Encode(v interface{}) error {    if enc.err != nil {        return enc.err    }    e := newEncodeState()    err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})    if err != nil {        return err    }    // Terminate each value with a newline.    // This makes the output look a little nicer    // when debugging, and some kind of space    // is required if the encoded value was a number,    // so that the reader knows there aren't more    // digits coming.    e.WriteByte('')    b := e.Bytes()    if enc.indentPrefix != "" || enc.indentValue != "" {        if enc.indentBuf == nil {            enc.indentBuf = new(bytes.Buffer)        }        enc.indentBuf.Reset()        err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)        if err != nil {            return err        }        b = enc.indentBuf.Bytes()    }    if _, err = enc.w.Write(b); err != nil {        enc.err = err    }    encodeStatePool.Put(e)    return err}

Encode方法通过encodeState的marshal方法进行序列化,这里它读取了enc.escapeHTML选项

实例

type User struct {    Name      string    Email     string    CreatedAt time.Time}type Users []*Userfunc reflectTypeDemo() {    logger, err := zap.NewProduction()    defer logger.Sync()    if err != nil {        panic(err)    }    var user = &User{        Name:      "hello1",        Email:     "hello1@test.com",        CreatedAt: time.Date(2020, 12, 19, 8, 0, 0, 0, time.UTC),    }    var users Users    users = append(users, &User{        Name:      "hello2",        Email:     "hello2@test.com",        CreatedAt: time.Date(2020, 12, 19, 9, 0, 0, 0, time.UTC),    }, &User{        Name:      "hello3",        Email:     "hello3@test.com",        CreatedAt: time.Date(2020, 12, 20, 10, 0, 0, 0, time.UTC),    })    logger.Sugar().Infow("hello", "user", user, "users", users)}

输出

{"level":"info","ts":1608350874.177944,"caller":"zap/zap_demo.go:42","msg":"hello","user":{"Name":"hello1","Email":"hello1@test.com","CreatedAt":"2020-12-19T08:00:00Z"},"users":[{"Name":"hello2","Email":"hello2@test.com","CreatedAt":"2020-12-19T09:00:00Z"},{"Name":"hello3","Email":"hello3@test.com","CreatedAt":"2020-12-20T10:00:00Z"}]}

小结

zap的sugar提供Infow方法,它通过sweetenFields方法来将key,value封装为Field;sweetenFields方法使用的是Any方法,它会根据value的类型返回不同的Field,如果value没有实现zapcore.ObjectMarshaler、zapcore.ArrayMarshaler,也不是基础类型,则走的是默认的Reflect(key, val);AddTo方法根据Field的类型做不同处理,如果是ReflectType类型,则执行的是enc.AddReflected(f.Key, f.Interface);jsonEncoder的AddReflected方法使用golang内置的json.Encoder来序列化。

doc

  • zap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值