在Go语言的标准库encoding/json中,默认解析JSON数字时会将其转换为float64类型,当JSON中的数值是int64范围的大整数时,float64的精度限制会导致数值丢失,比如常见的雪花算法生成的ID、大额交易金额等场景都会受到影响。下面介绍几种可保留int64数值的解析策略。

方案一:使用json.Number类型解析
json.Number是encoding/json库中提供的用于表示JSON数字的类型,它底层是字符串,不会自动转换为float64,我们可以在解析时指定字段类型为json.Number,之后再手动转换为int64。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID json.Number `json:"id"`
Name string `json:"name"`
}
func main() {
jsonStr := `{"id": 1234567890123456789, "name": "test"}`
var user User
// 使用json.Number解析,不会丢失精度
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
fmt.Println("解析错误:", err)
return
}
// 将json.Number转换为int64
id, err := user.ID.Int64()
if err != nil {
fmt.Println("转换int64错误:", err)
return
}
fmt.Printf("ID类型: %T, 值: %d\n", id, id)
}方案二:自定义UnmarshalJSON方法
如果希望结构体字段直接使用int64类型,不需要额外的转换步骤,可以为结构体实现json.Unmarshaler接口,自定义解析逻辑,直接处理int64数值。
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Product struct {
Price int64 `json:"price"`
}
// 实现json.Unmarshaler接口
func (p *Product) UnmarshalJSON(data []byte) error {
// 定义临时结构体,用json.Number接收数值
type tempProduct struct {
Price json.Number `json:"price"`
}
var tmp tempProduct
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
// 将json.Number转换为int64
price, err := strconv.ParseInt(tmp.Price.String(), 10, 64)
if err != nil {
return err
}
p.Price = price
return nil
}
func main() {
jsonStr := `{"price": 9223372036854775807}`
var product Product
err := json.Unmarshal([]byte(jsonStr), &product)
if err != nil {
fmt.Println("解析错误:", err)
return
}
fmt.Printf("价格: %d\n", product.Price)
}方案三:使用json.RawMessage延迟解析
当不确定JSON中某个字段的具体类型,或者需要先拿到原始字节再按需解析时,可以使用json.RawMessage类型,它保存了字段的原始JSON编码字节,我们可以在后续需要时再按照int64的规则解析。
package main
import (
"encoding/json"
"fmt"
)
type Order struct {
OrderID json.RawMessage `json:"order_id"`
Amount int64 `json:"amount"`
}
func main() {
jsonStr := `{"order_id": 1234567890123456789, "amount": 100}`
var order Order
// 第一步先解析到RawMessage
err := json.Unmarshal([]byte(jsonStr), &order)
if err != nil {
fmt.Println("解析错误:", err)
return
}
// 第二步解析order_id为int64
var orderID int64
err = json.Unmarshal(order.OrderID, &orderID)
if err != nil {
fmt.Println("order_id解析错误:", err)
return
}
fmt.Printf("订单ID: %d, 金额: %d\n", orderID, order.Amount)
}不同方案的选择建议
- 如果只需要简单处理单个int64字段,优先选择
json.Number方案,实现简单改动小。 - 如果希望结构体字段直接使用int64类型,不需要额外转换,选择自定义UnmarshalJSON方案。
- 如果JSON结构不固定,或者需要动态判断字段类型再解析,选择
json.RawMessage方案。
以上三种方案都可以有效避免Go语言解析JSON时int64数值的精度丢失问题,开发者可以根据实际的业务场景选择最合适的实现方式。
GoJSON解析int64int64_precision修改时间:2026-06-05 22:21:11