Problems with Unmarshal in golang

In the json specification, there is no distinction between integer and floating-point types for numeric types, so go uses float64 for mapping, but there is a hidden danger. If the safe integer range of float64 is exceeded, the precision will be lost.
When using interface{} to receive integers, Marshal again needs to pay attention to the problem of loss of precision.

The largest safe integer of float64 is 52-bit mantissa all 1 and the exponent part is the minimum 0x001F FFFF FFFF FFFF The
largest integer that can be stored in float64 is 52-bit mantissa all 1 and the exponent part is the maximum 0x07FEF FFFF FFFF FFFF Decimal
significant digits are in 16 bits ( max = 9007199254740991), if it exceeds, the precision may be lost

Solution:

Clearly use int to receive, do not use interface{}
to use decoder, set useNumber=true, and parse large numbers

decoder := json.NewDecoder(bytes.NewReader(request))
decoder.UseNumber() // set useNumber = true
err := decoder.Decode(&req)

After setting UseNumber, the number will be treated as json.Number type, and the bottom layer is string.

// A Number represents a JSON number literal.
type Number string
// String returns the literal text of the number.
func (n Number) String() string {
    
     return string(n) }
// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
    
    
   return strconv.ParseFloat(string(n), 64)
}
// json.newTypeEcnode -- 记录对应类型的序列化方法

Use tags to implement additional requirements (add after the specified name, and parameters):

omitempty: json: "name,omitempty" can be ignored when the value is 0 or empty

string/number/boolean: json: "name, string" can be specified to convert the type to string when serializing. In addition, you can also choose number and boolean

To sum up, we need to pay attention to the following points when using the receiver:

The receiver needs to be a pointer type

If the type is clear, use struct & to set the json tag to "-", which helps to filter unnecessary fields. At the same time, compared with map, it can determine the field type, reduce the steps of judging the type, and the effect is better

The useNumber of the decodeState used by default is false, and the type used by the receiver is interface{}, and there is a case of loss of precision (when it exceeds the safe integer range of float64)

decoder and Unmarshal options:

json.Decoder is suitable for io.Reader streams, or needs to decode multiple values ​​from a data stream
json.Unmarshal is suitable for existing JSON data in memory
by writing MarshalJSON()([]byte, error) and UnmarshalJSON(b []byte) error To implement custom JSON serialization and deserialization

Do not serialize and deserialize frequently, try to solve it once

A lot of recursion and reflection affect performance and can be optimized (similar to protobuf generated code parsing)

Guess you like

Origin blog.csdn.net/qq_30505673/article/details/130961401