【发布时间】:2019-12-15 15:53:25
【问题描述】:
我遇到了一些整数溢出错误。 我有一个使用 golang 和 go-micro 作为微服务框架构建的微服务应用程序。 我使用 NATS 作为消息代理。
我的微服务有效负载格式为
map[string]interface{}
当我发布包含 uint64 的有效负载时会出现问题,例如
var id uint64 = 512281913614499841
message := map[string]inteface{}
message["id"] = id
(这是由 cockroachdb 生成的唯一 ID),当订阅者接收到此消息作为字节并将其解组到 uint64 时,我意识到发生溢出并且值变为
512281913614499840 //this should be 512281913614499841
注意末尾的 0 而不是 1
我创建了 2 个函数(overFlowError 和 noOverflow) - 见下文。
overFlowError 函数模拟导致溢出的代码
并且 noOverflow 打印正确的结果,因为我使用这种格式的有效负载 map[string][struct] 而不是 map[string]interface
type UserType struct {
Email string `json:"email"`
ID int64 `json:"id"`
}
func overFlowError() {
var id int64 = 512281913614499841
user := UserType{
Email: "example",
ID: id,
}
message := map[string]interface{}{
"data": user,
}
//mashal to byte to simulate service payload
servicePayload, err := json.Marshal(message)
if err != nil {
log.Println(err)
}
var receivedMessage map[string]interface{}
json.Unmarshal(servicePayload, &receivedMessage)
var myUser UserType
mapstructure.Decode(receivedMessage["data"], &myUser)
log.Println("---receivedMessage:", myUser.ID) //prints 512281913614499840 - incorrect
}
没有溢出
type UserType struct {
Email string `json:"email"`
ID int64 `json:"id"`
}
func noOverflow() {
var id int64 = 512281913614499841
message := map[string]UserType{}
message["data"] = UserType{
Email: "example",
ID: id,
}
byteMessage, err := json.Marshal(message)
if err != nil {
log.Println(err)
}
var msgMap map[string]UserType
json.Unmarshal(byteMessage, &msgMap)
log.Println("---myUser:", msgMap["data"].ID) // prints 512281913614499841 - correct
}
为了避免大量代码重写,我只剩下第一个选项,我在 overFlowError 函数中模拟并在上面解释过
这个问题有解决办法吗?
【问题讨论】:
-
能否将您的代码库中的代码添加到此问题中?
-
这是因为
id的值超出了float64的精度范围。您可以将其编组为字符串并在接收时对其进行解析,或者将json.Decoder与json.Decoder.UseNumber一起使用而不是json.Unmarshal然后解析数字。 -
谢谢leaf,我之前尝试了第一个解决方案,但是感觉不是最好的解决方案,因为字符串不是预期的类型。我正在寻找更自然、更优雅的解决方案。对于第二个解决方案,我正在考虑如何处理结构中的 uint64 字段,例如: type User struct{ID uint64} 因为这在反序列化时也会溢出。我看看 json.decoder 包
-
@ykel 您从
ID字段中查看了哪些数字属性,以便您不希望它成为字符串?你是加、减、除还是乘? -
@zerkms,如果没有其他更好的方法,我将使用叶子的第一个解决方案。
标签: go