带有长数字的 JSON 解组给出浮点数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22343083/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 17:11:46  来源:igfitidea点击:

JSON unmarshaling with long numbers gives floating point number

jsonfloating-pointgomarshalling

提问by Fersca

I was marshaling and unmarshaling JSONs using golang and when I want to do it with number fields golang transforms it in floating point numbers instead of use long numbers, for example.

例如,我正在使用 golang 对 JSON 进行编组和解组,当我想对数字字段进行处理时,golang 会将其转换为浮点数而不是长数字。

I have the following JSON:

我有以下 JSON:

{
    "id": 12423434, 
    "Name": "Fernando"
}

After marshalit to a map and unmarshalagain to a json string I get:

marshal它到地图并unmarshal再次到 json 字符串之后,我得到:

{
    "id":1.2423434e+07,
    "Name":"Fernando"
}

As you can see the "id"field is in floating point notation.

如您所见,该"id"字段采用浮点表示法。

The code that I am using is the following:

我正在使用的代码如下:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {

    //Create the Json string
    var b = []byte(`
        {
        "id": 12423434, 
        "Name": "Fernando"
        }
    `)

    //Marshal the json to a map
    var f interface{}
    json.Unmarshal(b, &f)
    m := f.(map[string]interface{})

    //print the map
    fmt.Println(m)

    //unmarshal the map to json
    result,_:= json.Marshal(m)

    //print the json
    os.Stdout.Write(result)

}

It prints:

它打印:

map[id:1.2423434e+07 Name:Fernando]
{"Name":"Fernando","id":1.2423434e+07}

It appears to be that the first marshalto the map generates the FP. How can I fix it to a long?

似乎是marshal地图的第一个生成 FP。我怎样才能把它修好?

This is the link to the program in the goland playground: http://play.golang.org/p/RRJ6uU4Uw-

这是goland playground中程序的链接:http://play.golang.org/p/RRJ6uU4Uw-

回答by rog

There are times when you cannot define a struct in advance but still require numbers to pass through the marshal-unmarshal process unchanged.

有时您无法提前定义结构,但仍需要数字不变地通过 marshal-unmarshal 过程。

In that case you can use the UseNumbermethod on json.Decoder, which causes all numbers to unmarshal as json.Number(which is just the original string representation of the number). This can also useful for storing very big integers in JSON.

在这种情况下,您可以使用UseNumberon 方法json.Decoder,这会导致所有数字解组为json.Number(这只是数字的原始字符串表示形式)。这对于在 JSON 中存储非常大的整数也很有用。

For example:

例如:

package main

import (
    "strings"
    "encoding/json"
    "fmt"
    "log"
)

var data = `{
    "id": 12423434, 
    "Name": "Fernando"
}`

func main() {
    d := json.NewDecoder(strings.NewReader(data))
    d.UseNumber()
    var x interface{}
    if err := d.Decode(&x); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("decoded to %#v\n", x)
    result, err := json.Marshal(x)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("encoded to %s\n", result)
}

Result:

结果:

decoded to map[string]interface {}{"id":"12423434", "Name":"Fernando"}
encoded to {"Name":"Fernando","id":12423434}

回答by ANisus

The JSON standarddoesn't have longs or floats, it only has numbers. The jsonpackage will assume float64 when you haven't defined anything else (meaning, only provided Unmarshalwith an interface{}).

JSON标准没有多头或浮动,它只有数字。json当您没有定义任何其他内容时,该包将假定为 float64(意思是,只提供Unmarshal了一个interface{})。

What you should do is to create a proper struct (as Volker mentioned):

您应该做的是创建一个适当的结构(如 Volker 所述):

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Person struct {
    Id   int64  `json:"id"`
    Name string `json:"name"`
}

func main() {

    //Create the Json string
    var b = []byte(`{"id": 12423434, "Name": "Fernando"}`)

    //Marshal the json to a proper struct
    var f Person
    json.Unmarshal(b, &f)

    //print the person
    fmt.Println(f)

    //unmarshal the struct to json
    result, _ := json.Marshal(f)

    //print the json
    os.Stdout.Write(result)
}

Result:

结果:

{12423434 Fernando}
{"id":12423434,"name":"Fernando"}

{12423434 费尔南多}
{"id":12423434,"name":"Fernando"}

Playground: http://play.golang.org/p/2R76DYVgMK

游乐场:http: //play.golang.org/p/2R76DYVgMK

Edit:

编辑:

In case you have a dynamic json structure and wish to use the benefits of a struct, you can solve it using json.RawMessage. A variable of type json.RawMessagewill store the raw JSON string so that you later on, when you know what kind of object it contains, can unmarshal it into the proper struct. No matter what solution you use, you will in any case need some ifor switchstatement where you determine what type of structure it is.

如果您有一个动态 json 结构并希望使用结构的好处,您可以使用json.RawMessage. 类型的变量json.RawMessage将存储原始 JSON 字符串,以便您稍后在知道它包含的对象类型时将其解组为正确的结构。无论您使用什么解决方案,在任何情况下您都需要一些ifswitch语句来确定它是什么类型的结构。

It is also useful when parts of the JSON data will only be copied to the another JSON object such as with the id-value of a JSON RPC request.

当部分 JSON 数据仅被复制到另一个 JSON 对象(例如使用idJSON RPC 请求的-value)时,它也很有用。

Example of container struct using json.RawMessage and the corresponding JSON data:

使用 json.RawMessage 和相应 JSON 数据的容器结构示例:

type Container struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

var b = []byte(`{"type": "person", "data":{"id": 12423434, "Name": "Fernando"}}`)

A modified version of your example on Playground: http://play.golang.org/p/85s130Sthu

您在 Playground 上的示例的修改版本:http: //play.golang.org/p/85s130Sthu

Edit2:

编辑2:

If the structure of your JSON value is based on the name of a name/value pair, you can do the same with a:

如果 JSON 值的结构基于名称/值对的名称,则可以使用以下命令执行相同操作:

type Container map[string]json.RawMessage