web-dev-qa-db-ja.com

長い数値でのJSONアンマーシャリングは浮動小数点数を与えます

私はgolangを使用してJSONをマーシャリングおよびアンマーシャリングしていましたが、数値フィールドでそれを行いたい場合、たとえばgolangは長い数値を使用する代わりに浮動小数点数に変換します。

次のJSONがあります。

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

marshalをマップに、unmarshalをjson文字列に再度追加すると、次のようになります。

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

ご覧の通り、"id"フィールドは浮動小数点表記です。

私が使用しているコードは次のとおりです。

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)

}

以下を印刷します。

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

マップの最初のmarshalがFPを生成しているようです。どうすればそれを長く修正できますか?

これはgolandプレイグラウンドのプログラムへのリンクです: http://play.golang.org/p/RRJ6uU4Uw-

48
Fersca

構造体を事前に定義できない場合でも、マーシャリングとアンマーシャリングのプロセスを変更せずに渡すために数値が必要な場合があります。

その場合、json.DecoderUseNumberメソッドを使用できます。これにより、すべての数値がjson.Number(数値の元の文字列表現)として非整列化されます。これは非常に大きな整数をJSONに保存する場合にも役立ちます。

例えば:

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)
}

結果:

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

JSON標準 にはlongやfloatはなく、数字のみがあります。 jsonパッケージは、他に何も定義していない場合にfloat64を想定します(つまり、interface{}Unmarshalのみを提供します)。

あなたがすべきことは、適切な構造体を作成することです(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)
}

結果:

{12423434フェルナンド}
{"id":12423434、 "name": "Fernando"}

遊び場: http://play.golang.org/p/2R76DYVgMK

編集:

動的なjson構造があり、構造の利点を使用したい場合は、json.RawMessageを使用して解決できます。タイプjson.RawMessageの変数は生のJSON文字列を保存するため、後でどの種類のオブジェクトが含まれているかがわかったときに、適切な構造体にマーシャリング解除できます。どのソリューションを使用する場合でも、どのタイプの構造であるかを決定するifまたはswitchステートメントが必要になります。

JSON RPCリクエストのid- valueなどを使用して、JSONデータの一部を別のJSONオブジェクトにのみコピーする場合にも役立ちます。

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"}}`)

Playgroundのサンプルの修正バージョン: http://play.golang.org/p/85s130Sth

Edit2:

JSON値の構造が名前と値のペアの名前に基づいている場合、次の方法で同じことができます。

type Container map[string]json.RawMessage
15
ANisus