fix(cast): 修复 JSON 反序列化到 interface{} 时跳过对象/数组的问题,并优化 int64 精度 (by AI)

This commit is contained in:
AI Engineer 2026-05-05 22:32:13 +08:00
parent e052313014
commit dd63c8eae8
2 changed files with 38 additions and 1 deletions

View File

@ -1,5 +1,11 @@
# CHANGELOG
## [v1.2.8] - 2026-05-05
### Fixed
- **JSON 解码器深度增强**: 修复了 `cast.UnmarshalJSON` 在反序列化到 `interface{}` 类型字段时会跳过对象和数组的重大缺陷。
- **高精度整数解析**: 优化了 JSON 解码过程中的数字处理逻辑。当目标为 `interface{}` 时,优先将整数解析为 `int64` 而非 `float64`彻底解决了纳秒级时间戳Nanosecond Timestamp和 64 位长 ID 的精度丢失问题。
- **接口兼容性**: 完善了对 `interface{}` 类型的自动类型识别,支持正确解析为 `map[string]any``[]any`
## [v1.2.6] - 2026-05-04
### Fixed
- **Map 深度合并修复**: 修复了在 `Convert``ToMap` 过程中,如果目标 Map 已存在该 Key其原有结构体/Map 值会被直接覆盖而非深度合并的问题。通过引入 `dst.MapIndex` 预读取与临时寻址变量,现已完美支持 Map 下非指针结构体的局部字段覆盖。

View File

@ -103,8 +103,24 @@ func (d *decoder) decodeValue(reflectValue reflect.Value, timeFormat string) err
switch char {
case '{':
if reflectValue.Kind() == reflect.Interface {
m := make(map[string]any)
if err := d.decodeObject(reflect.ValueOf(&m).Elem()); err != nil {
return err
}
reflectValue.Set(reflect.ValueOf(m))
return nil
}
return d.decodeObject(reflectValue)
case '[':
if reflectValue.Kind() == reflect.Interface {
var s []any
if err := d.decodeArray(reflect.ValueOf(&s).Elem()); err != nil {
return err
}
reflectValue.Set(reflect.ValueOf(s))
return nil
}
return d.decodeArray(reflectValue)
case '"':
str, err := d.parseString()
@ -123,6 +139,8 @@ func (d *decoder) decodeValue(reflectValue reflect.Value, timeFormat string) err
reflectValue.SetFloat(Float64(str))
case reflect.Bool:
reflectValue.SetBool(Bool(str))
case reflect.Interface:
reflectValue.Set(reflect.ValueOf(str))
default:
// 尝试将字符串解析为具体对象(比如内部又是 JSON
if strings.HasPrefix(str, "{") || strings.HasPrefix(str, "[") {
@ -148,9 +166,22 @@ func (d *decoder) decodeValue(reflectValue reflect.Value, timeFormat string) err
case reflect.String:
reflectValue.SetString(literal)
case reflect.Interface:
// 优先作为数字处理以保留精度 (int64)
if literal == "true" {
reflectValue.Set(reflect.ValueOf(true))
} else if literal == "false" {
reflectValue.Set(reflect.ValueOf(false))
} else if literal == "null" {
reflectValue.Set(reflect.Zero(reflectValue.Type()))
} else if strings.Contains(literal, ".") || strings.Contains(literal, "e") || strings.Contains(literal, "E") {
reflectValue.Set(reflect.ValueOf(Float64(literal)))
} else if i, err := strconv.ParseInt(literal, 10, 64); err == nil {
reflectValue.Set(reflect.ValueOf(i))
} else {
reflectValue.Set(reflect.ValueOf(literal))
}
}
}
return nil
}