Unmarshalling values in scientific notion to integers in Go

huangapple go评论85阅读模式
英文:

Unmarshalling values in scientific notion to integers in Go

问题

在我的Go代码中,我正在处理从一个端点接收到的JSON数据。这个端点将大的数值使用科学计数法进行编码:

type Test struct {
    Key   string
    Value int32
}

func main() {
    data := []byte("{\"Key\": \"derp\", \"Value\": 3.898733e+06}")

    var t *Test
    err := json.Unmarshal(data, &t)
    
    fmt.Printf("Error: %v\n", err)
    fmt.Printf("Data: %v\n", t)
}

这里编码的值等同于标准表示法中的3,898,733。然而,这段代码打印出了一个错误:

json: cannot unmarshal number 3.898733e+06 into Go struct field Test.Value of type int32

这是有道理的,因为strconv也无法将这个值从字符串解析出来。然而,我可以使用var i int32 = 3.898733e+06,它可以编译并产生正确的结果。

那么,我该如何解决这个错误呢?

英文:

In my Go code, I was working to unmarshal a JSON payload we receive from an endpoint. This endpoint encodes large values in scientific notation:

type Test struct {
	Key   string
	Value int32
}

func main() {
	data := []byte("{\"Key\": \"derp\", \"Value\": 3.898733e+06}")

	var t *Test
	err := json.Unmarshal(data, &t)
	
	fmt.Printf("Error: %v\n", err)
	fmt.Printf("Data: %v\n", t)
}

The encoded value here is equivalent to 3,898,733 in standard notation. However, this code prints an error:

> json: cannot unmarshal number 3.898733e+06 into Go struct field Test.Value of type int32

This makes sense because strconv also fails to parse this value from a string. However, I can do var i int32 = 3.898733e+06 and that compiles and produces the correct answer.

So, how can I address this error?

答案1

得分: 1

声明var i int32 = 3.898733e+06是有效的,因为该表达式中的字面量是一个无类型常量,无类型常量根据上下文进行求值。在这种情况下,即使它被写成浮点数,它在编译时被解释为int32。这不会在运行时发生。

有几种选项可以使其适用于JSON编组:

1)将Value声明为json.Number。这样,您可以尝试将其解析为int64,如果失败,则解析为float64,并转换为int64,希望不会丢失精度。
2)定义一个自定义类型并自行进行解组:

type LongInt int32

func (i *LongInt) UnmarshalJSON(data []byte) error {
   // 自行解析数据并设置int值
   // 可以使用big.Int吗?
}

3)将Value声明为float64

英文:

The declaration var i int32 = 3.898733e+06 works because the literal in this expression is an untyped constant, and untyped constants are evaluated based on context. In this case, even though it is written as a floating-point number, it is interpreted as an int32 at compile time. This does not happen at runtime.

There are several options to make this work for JSON marshaling:

  1. Declare the Value as json.Number. This way you can try parsing it as int64, and if that fails, parse it as float64, and convert to int64 and hope you don't lose precision.
  2. Define a custom type and unmarshal yourself:
type LongInt int32

func (i *LongInt) UnmarshalJSON(data []byte) error {
   // Parse data yourself and set the int value
   // Maybe use big.Int?
}
  1. Declare Value as float64

huangapple
  • 本文由 发表于 2022年6月9日 10:50:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/72554209.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定