
go 的 json.unmarshal 默认不支持将科学计数法(如 1.2e+8)直接解析为 uint64/int64 等整型字段,会静默失败并置零;需改用 float64 接收后再显式转换,或通过自定义 unmarshaljson 方法安全处理。
go 的 json.unmarshal 默认不支持将科学计数法(如 1.2e+8)直接解析为 uint64/int64 等整型字段,会静默失败并置零;需改用 float64 接收后再显式转换,或通过自定义 unmarshaljson 方法安全处理。
在 Go 中,encoding/json 包对 JSON 数字的反序列化有明确类型约束:当目标字段为整型(如 uint64、int64)时,JSON 解析器仅接受不含小数点和指数符号的纯整数字符串(如 "120000000"),而拒绝 1.2E+8、1.2e8 或 120000000.0 等浮点格式——即使该值在数学上可精确表示为整数。此时解析不会报错,但字段会被默认初始化为 0,导致静默数据丢失。
✅ 正确做法:使用 float64 + 显式转换(推荐)
最简洁可靠的方式是将结构体字段声明为 float64,再在业务逻辑中安全转为整型:
type Person struct {
Id float64 `json:"id"`
Name string `json:"name"`
}
func main() {
var b = []byte(`{"id": 1.2E+8, "Name": "Fernando"}`)
var f Person
if err := json.Unmarshal(b, &f); err != nil {
panic(err)
}
// 安全转换:检查是否为整数值
if f.Id == float64(int64(f.Id)) {
idInt := int64(f.Id)
fmt.Printf("Parsed ID: %d (as int64)\n", idInt) // 输出: Parsed ID: 120000000
} else {
fmt.Println("Warning: ID is not a whole number")
}
}⚠️ 注意:float64 可精确表示 ≤ 2⁵³ 的整数,对大多数 ID 场景(如数据库主键、时间戳毫秒)完全足够;若 ID 超出此范围(如超大哈希值),应改用字符串存储或自定义解析。
? 进阶方案:实现 UnmarshalJSON 接口(更健壮)
为彻底解耦类型与解析逻辑,可为字段封装自定义类型,并实现 json.UnmarshalJSON:
type SafeUint64 uint64
func (u *SafeUint64) UnmarshalJSON(data []byte) error {
var f float64
if err := json.Unmarshal(data, &f); err != nil {
// 尝试作为字符串解析(兼容 "123" 或 "1.2E+8" 字符串形式)
var s string
if err2 := json.Unmarshal(data, &s); err2 == nil {
if v, err3 := strconv.ParseFloat(s, 64); err3 == nil {
f = v
} else {
return fmt.Errorf("invalid number string: %s", s)
}
} else {
return err
}
}
if f < 0 || f > math.MaxUint64 || f != float64(uint64(f)) {
return fmt.Errorf("number %g out of uint64 range or not integer", f)
}
*u = SafeUint64(f)
return nil
}
type Person struct {
Id SafeUint64 `json:"id"`
Name string `json:"name"`
}这样即可直接支持 1.2E+8、120000000、"1.2E+8" 等多种输入格式,且具备溢出和精度校验。
? 总结
- ❌ 不要直接用 uint64/int64 接收含指数的 JSON 数字;
- ✅ 优先用 float64 + 业务层转换,简单高效;
- ? 对强类型要求场景,实现 UnmarshalJSON 接口,兼顾灵活性与安全性;
- ? 始终检查 json.Unmarshal 返回的 error,避免静默失败。
科学计数法是 JSON 标准的一部分,Go 的设计选择是出于类型安全考量,而非 bug——理解这一机制,才能写出健壮的 JSON 处理代码。


















