Go RPC传输中如何保留非结构化JSON的整数类型?
在Go中JSON编解码全程保留整数类型的解决方案
针对你遇到的uint64类型在JSON编解码+RPC传输后转为float64、丢失原始类型的问题,有以下几种可行方案:
方案一:使用json.Number配合解码器UseNumber选项
Go标准库的encoding/json提供了json.Number类型和Decoder.UseNumber()方法,能将JSON数字以字符串形式暂存,避免自动转为float64,后续可还原为原始整数类型。
代码示例:
import ( "bytes" "encoding/json" "fmt" "strconv" ) func main() { // 构建map时将uint64转为json.Number存储 originalMap := map[string]interface{}{ "config": map[string]interface{}{ "port": json.Number(strconv.FormatUint(80, 10)), }, } // 序列化JSON data, err := json.Marshal(originalMap) if err != nil { panic(err) } // 反序列化时启用UseNumber,保留数字的原始字符串形式 var decodedMap map[string]interface{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.UseNumber() if err = decoder.Decode(&decodedMap); err != nil { panic(err) } // 将json.Number转回uint64 configMap, ok := decodedMap["config"].(map[string]interface{}) if !ok { panic("config is not a map") } portNum, ok := configMap["port"].(json.Number) if !ok { panic("port is not a json.Number") } port, err := portNum.Uint64() if err != nil { panic(err) } fmt.Printf("Port值:%d,类型:%T\n", port, port) // 输出:Port值:80,类型:uint64 }
方案二:用自定义结构体替代map[string]interface{}
如果你的数据结构是可预知的,优先使用自定义结构体。结构体字段明确指定类型后,JSON编解码会严格遵循字段类型,完全避免interface{}导致的类型丢失问题。
代码示例:
import ( "encoding/json" "fmt" ) // 定义对应的数据结构体 type Config struct { Port uint64 `json:"port"` } type AppConfig struct { Config Config `json:"config"` } func main() { original := AppConfig{ Config: Config{Port: 80}, } // 序列化 data, err := json.Marshal(original) if err != nil { panic(err) } // 反序列化回结构体 var decoded AppConfig if err = json.Unmarshal(data, &decoded); err != nil { panic(err) } fmt.Printf("Port值:%d,类型:%T\n", decoded.Config.Port, decoded.Config.Port) // 输出:Port值:80,类型:uint64 }
方案三:使用第三方JSON序列化库
部分第三方JSON库提供了保留整数类型的配置,可直接将JSON数字解析为int64/uint64而非float64,无需手动处理json.Number。这类库通常API与标准库兼容,迁移成本低。
内容的提问来源于stack exchange,提问作者Abhishek Karigar
相关产品推荐
相关产品推荐

