GoでJSONを使用する方法
著者は、 Diversity in Tech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
最新のプログラムでは、あるプログラムと別のプログラムの間で通信することが重要です。 ユーザーが別のプログラムにアクセスできるかどうかをチェックするGoプログラム、Webサイトに表示する過去の注文のリストを取得する JavaScript プログラム、または Rust [X183X ]プログラムはファイルからテスト結果を読み取ります。プログラムには、他のプログラムにデータを提供する方法が必要です。 ただし、多くのプログラミング言語には、他の言語が理解できない独自のデータを内部に格納する方法があります。 これらの言語が相互作用できるようにするには、データをすべての言語が理解できる共通の形式に変換する必要があります。 これらの形式の1つであるJSONは、インターネット上および同じシステム内のプログラム間でデータを送信するための一般的な方法です。
最新のプログラミング言語の多くには、標準ライブラリでJSONとの間でデータを変換する方法が含まれています。Goも同様です。 Goが提供するencoding/ json パッケージを使用することで、GoプログラムはJSONを使用して通信できる他のシステムとも対話できるようになります。
このチュートリアルでは、encoding/json
パッケージを使用してmap
からJSONデータにデータをエンコードするプログラムを作成し、次にstruct
タイプを使用するようにプログラムを更新します。代わりにデータをエンコードします。 その後、JSONデータをmap
にデコードするようにプログラムを更新してから、最終的にJSONデータをstruct
タイプにデコードします。
前提条件
このチュートリアルに従うには、次のものが必要です。
- Go version 1.16 or greater installed. To set this up, follow the How To Install Go tutorial for your operating system.
- JSONの概要にあるJSONの知識。
- Go構造体タグを使用して
struct
タイプのフィールドをカスタマイズする機能。 詳細については、Goで構造体タグを使用する方法を参照してください。 - 必要に応じて、Goで日付と時刻の値を作成する方法に注意してください。 詳細については、Goで日付と時刻を使用する方法を参照してください。
マップを使用してJSONを生成する
JSONのエンコードとデコードに対するGoのサポートは、標準ライブラリのencoding/json
パッケージによって提供されます。 そのパッケージから使用する最初の関数は、json.Marshal関数です。 マーシャリングは、シリアル化とも呼ばれ、メモリ内のプログラムデータを他の場所で送信または保存できる形式に変換するプロセスです。 次に、json.Marshal
関数を使用して、GoデータをJSONデータに変換します。 json.Marshal
関数は、JSONにマーシャリングする値としてinterface{}
タイプを受け入れるため、任意の値をパラメーターとして渡すことができ、結果としてJSONデータを返します。 このセクションでは、json.Marshal
関数を使用して、Go map
値からさまざまなタイプのデータを含むJSONを生成し、それらの値を出力に出力するプログラムを作成します。
ほとんどのJSONはオブジェクトとして表され、string
キーとその他のさまざまなタイプが値として使用されます。 このため、GoでJSONデータを生成する最も柔軟な方法は、string
キーとinterface{}
値を使用してデータをmap
に配置することです。 string
キーはJSONオブジェクトキーに直接変換でき、interface{}
値を使用すると、string
、int
、または別のmap[string]interface{}
。
プログラムでencoding/json
パッケージの使用を開始するには、プログラム用のディレクトリが必要です。 このチュートリアルでは、projects
という名前のディレクトリを使用します。
まず、projects
ディレクトリを作成し、次の場所に移動します。
mkdir projects cd projects
次に、プロジェクトのディレクトリを作成します。 この場合、ディレクトリjsondata
を使用します。
mkdir jsondata cd jsondata
jsondata
ディレクトリ内で、nano
またはお気に入りのエディタを使用して、main.go
ファイルを開きます。
nano main.go
main.go
ファイルに、main
関数を追加してプログラムを実行します。 次に、さまざまなキーとデータの種類を使用してmap[string]interface{}
値を追加します。 次に、json.Marshal
関数を使用して、map
データをJSONデータにマーシャリングします。
main.go
に次の行を追加します。
main.go
package main import ( "encoding/json" "fmt" ) func main() { data := map[string]interface{}{ "intValue": 1234, "boolValue": true, "stringValue": "hello!", "objectValue": map[string]interface{}{ "arrayValue": []int{1, 2, 3, 4}, }, } jsonData, err := json.Marshal(data) if err != nil { fmt.Printf("could not marshal json: %s\n", err) return } fmt.Printf("json data: %s\n", jsonData) }
data
変数には、各値のキーとしてstring
が含まれていることがわかりますが、これらのキーの値は異なります。 1つはint
値、もう1つはbool
値、もう1つは[]int
値を含む別のmap[string]interface{}
値です。
data
変数をjson.Marshal
に渡すと、関数は指定されたすべての値を調べて、それらがどのタイプであり、JSONでそれらをどのように表現するかを決定します。 変換に問題がある場合、json.Marshal
関数は問題を説明するerror
を返します。 ただし、変換が成功した場合、jsonData
変数にはマーシャリングされたJSONデータの[]byte
が含まれます。 []byte
値は、myString := string(jsonData)
、またはフォーマット文字列の%s
動詞を使用して、string
値に変換できるため、次に、fmt.Printf
を使用してJSONデータを画面に出力できます。
ファイルを保存して閉じます。
プログラムの出力を確認するには、go run
コマンドを使用して、main.go
ファイルを提供します。
go run main.go
出力は次のようになります。
Outputjson data: {"boolValue":true,"intValue":1234,"objectValue":{"arrayValue":[1,2,3,4]},"stringValue":"hello!"}
出力では、最上位のJSON値が、それを囲む中括弧({}
)で表されるオブジェクトであることがわかります。 data
に含めたすべての値が存在します。 また、objectValue
のmap[string]interface{}
が{}
で囲まれた別のJSONオブジェクトに変換され、配列値とともにarrayValue
が含まれていることもわかります。 [1,2,3,4]
の。
JSONでのエンコード時間
ただし、encoding/json
パッケージは、string
やint
の値などのタイプをサポートするだけではありません。 また、より複雑なタイプをエンコードすることもできます。 サポートされているより複雑なタイプの1つは、timeパッケージのtime.Time
タイプです。
注:Goのtime
パッケージの詳細については、チュートリアルGoで日付と時刻を使用する方法を確認してください。
これが実際に動作することを確認するには、main.go
ファイルを再度開き、time.Date
関数を使用してtime.Time
値をデータに追加します。
main.go
package main import ( "encoding/json" "fmt" "time" ) func main() { data := map[string]interface{}{ "intValue": 1234, "boolValue": true, "stringValue": "hello!", "dateValue": time.Date(2022, 3, 2, 9, 10, 0, 0, time.UTC), "objectValue": map[string]interface{}{ "arrayValue": []int{1, 2, 3, 4}, }, } ... }
この更新により、UTC
タイムゾーンの日付March 2, 2022,
と時刻9:10:00 AM
がdateValue
キーに割り当てられます。
変更を保存したら、前と同じgo run
コマンドを使用してプログラムを再実行します。
go run main.go
出力は次のようになります。
Outputjson data: {"boolValue":true,"dateValue":"2022-03-02T09:10:00Z","intValue":1234,"objectValue":{"arrayValue":[1,2,3,4]},"stringValue":"hello!"}
今回の出力では、JSONデータにdateValue
フィールドが表示され、時刻は RFC 3339 形式でフォーマットされています。これは、日付と時刻をstring
値。
null
値をJSONでエンコードする
プログラムが対話するシステムによっては、JSONデータでnull
値を送信する必要がある場合があり、Goのencoding/json
パッケージでもそれを処理できます。 map
を使用すると、nil
値を持つ新しいstring
キーを追加するだけです。
いくつかのnull
値をJSON出力に追加するには、main.go
ファイルを再度開き、次の行を追加します。
main.go
... func main() { data := map[string]interface{}{ "intValue": 1234, "boolValue": true, "stringValue": "hello!", "dateValue": time.Date(2022, 3, 2, 9, 10, 0, 0, time.UTC), "objectValue": map[string]interface{}{ "arrayValue": []int{1, 2, 3, 4}, }, "nullStringValue": nil, "nullIntValue": nil, } ... }
データに追加した値には、string
値またはint
値であるというキーがありますが、実際には、これらの値のいずれかを作成しているコードはありません。 map
にはinterface{}
の値があるため、コードはinterface{}
の値がnil
であることを知っています。 このmap
を使用してGoデータからJSONデータに変換するだけなので、この時点での区別は違いはありません。
main.go
に変更を保存したら、go run
を使用してプログラムを実行します。
go run main.go
出力は次のようになります。
Outputjson data: {"boolValue":true,"dateValue":"2022-03-02T09:10:00Z","intValue":1234,"nullIntValue":null,"nullStringValue":null,"objectValue":{"arrayValue":[1,2,3,4]},"stringValue":"hello!"}
出力には、nullIntValue
フィールドとnullStringValue
フィールドがJSONnull
値に含まれていることがわかります。 このようにして、map[string]interface{}
値を使用して、Goデータを期待されるフィールドを持つJSONデータに変換できます。
このセクションでは、map[string]interface{}
値をJSONデータにマーシャリングできるプログラムを作成しました。 次に、time.Time
フィールドをデータに追加し、null
値フィールドのペアも含めました。
map[string]interface{}
を使用してJSONデータをマーシャリングすることは非常に柔軟ですが、同じデータを複数の場所に送信する必要がある場合は面倒になる可能性もあります。 このデータをコード内の複数の場所にコピーすると、誤ってフィールド名を誤って入力したり、誤ったデータをフィールドに割り当てたりする可能性があります。 このような場合は、struct
タイプを使用して、JSONに変換するデータを表すと便利な場合があります。
Structを使用してJSONを生成する
Goのような静的に型付けされた言語を使用する利点の1つは、これらの型を使用して、コンパイラーにプログラムの整合性をチェックまたは強制させることができることです。 Goのencoding/json
パッケージでは、JSONデータを表すstruct
タイプを定義することで、これを利用できます。 struct
に含まれるデータが、構造体タグを使用してどのように変換されるかを制御できます。 このセクションでは、map
タイプの代わりにstruct
タイプを使用してJSONデータを生成するようにプログラムを更新します。
struct
を使用してJSONデータを定義する場合、翻訳されると予想されるフィールド名(struct
タイプ名自体ではない)をエクスポートする必要があります。つまり、大文字で始まる必要があります。 IntValue
、またはencoding/json
パッケージは、フィールドにアクセスしてJSONに変換することができなくなります。 これらのフィールドの名前を制御するために構造体タグを使用しない場合、フィールド名はstruct
の場合と同じように直接変換されます。 データの形成方法によっては、デフォルトの名前を使用することがJSONデータで希望する場合があります。 この場合、構造体タグを追加する必要はありません。 ただし、多くのJSONコンシューマーは、フィールド名にintValue
やint_value
などの名前形式を使用するため、これらの構造体タグを追加すると、その変換の実行方法を制御できます。
たとえば、JSONにマーシャリングしたIntValue
というフィールドを持つstruct
があるとします。
type myInt struct { IntValue int } data := &myInt{IntValue: 1234}
json.Marshal
関数を使用してdata
変数をJSONにマーシャリングした場合、次の値になります。
{"IntValue":1234}
ただし、JSONコンシューマーが、フィールドの名前がIntValue
ではなくintValue
であることを期待している場合は、encoding/json
を通知する方法が必要になります。 json.Marshal
は、JSONデータでフィールドの名前が何であるかを認識していないため、フィールドに構造体タグを追加することで通知します。 json
構造体タグをIntValue
フィールドにintValue
の値で追加することにより、json.Marshal
にintValue
という名前を使用するように指示します。 JSONデータを生成する場合:
type myInt struct { IntValue int `json:"intValue"` } data := &myInt{IntValue: 1234}
今回、data
変数をJSONにマーシャリングすると、json.Marshal
関数はjson
構造体タグを認識し、フィールドにintValue
という名前を付けることができます。期待どおりの結果が得られます:
{"intValue":1234}
次に、JSONデータにstruct
値を使用するようにプログラムを更新します。 myJSON
struct
タイプを追加してトップレベルのJSONオブジェクトを定義し、myObject
struct
を追加して内部JSONオブジェクトを定義します。 ObjectValue
フィールド。 また、json
構造体タグを各フィールドに追加して、json.Marshal
にJSONデータでの名前の付け方を指示します。 また、data
変数の割り当てを更新して、myJSON
構造体を使用し、他のGostruct
と同様に宣言する必要があります。
main.go
ファイルを開き、次の変更を加えます。
main.go
... type myJSON struct { IntValue int `json:"intValue"` BoolValue bool `json:"boolValue"` StringValue string `json:"stringValue"` DateValue time.Time `json:"dateValue"` ObjectValue *myObject `json:"objectValue"` NullStringValue *string `json:"nullStringValue"` NullIntValue *int `json:"nullIntValue"` } type myObject struct { ArrayValue []int `json:"arrayValue"` } func main() { otherInt := 4321 data := &myJSON{ IntValue: 1234, BoolValue: true, StringValue: "hello!", DateValue: time.Date(2022, 3, 2, 9, 10, 0, 0, time.UTC), ObjectValue: &myObject{ ArrayValue: []int{1, 2, 3, 4}, }, NullStringValue: nil, NullIntValue: &otherInt, } ... }
これらの変更の多くは、以前のIntValue
フィールド名の例に似ていますが、一部の変更は具体的に呼び出す必要があります。 それらの1つであるObjectValue
フィールドは、*myObject
の参照型を使用して、JSONマーシャラーにmyObject
値または[のいずれかへの参照を期待するように指示しています。 X160X]値。 これは、カスタムオブジェクトの複数のレイヤーであるJSONオブジェクトを定義する方法です。 JSONデータで必要な場合は、myObject
タイプ内で別のstruct
タイプを参照することもできます。 このパターンを使用すると、Gostruct
タイプを使用して非常に複雑なJSONオブジェクトを記述できます。
上記のコードで確認するもう1つのフィールドのペアは、NullStringValue
とNullIntValue
です。 StringValue
およびIntValue
とは異なり、これらの値のタイプは参照タイプ*string
および*int
です。 デフォルトでは、string
およびint
タイプは、「空の」値が""
および0
であるため、nil
の値を持つことはできません。 したがって、1つのタイプまたはnil
のいずれかであるフィールドを表す場合は、それを参照にする必要があります。 たとえば、ユーザーアンケートがあり、ユーザーが質問に回答しないことを選択した場合(null
の値)を表すことができるようにしたいとします。 ""
値)。
このコードは、NullIntValue
フィールドを更新して、4321
の値を割り当て、*int
などの参照型に値を割り当てる方法を示します。 Goでは、変数を使用して、int
やstring
などのプリミティブタイプへの参照のみを作成できます。 したがって、NullIntValue
フィールドに値を割り当てるには、最初に値を別の変数otherInt
に割り当て、次に&otherInt
を使用してその値への参照を取得します(代わりに&4321
を直接実行すること)。
更新を保存したら、go run
を使用してプログラムを実行します。
go run main.go
出力は次のようになります。
Outputjson data: {"intValue":1234,"boolValue":true,"stringValue":"hello!","dateValue":"2022-03-02T09:10:00Z","objectValue":{"arrayValue":[1,2,3,4]},"nullStringValue":null,"nullIntValue":4321}
この出力は、map[string]interface{}
値を使用した場合と同じですが、今回はnullIntValue
の値が4321
であるため、[の値であることがわかります。 X155X]。
最初は、struct
値の設定に余分な時間がかかる場合がありますが、一度定義すると、コードで何度も使用できるようになり、どこで使用しても結果は同じになります。彼ら。 map
が使用される可能性のあるすべての場所を検索する代わりに、それらを1つの場所で更新することもできます。
GoのJSONマーシャラーでは、値が空かどうかに基づいて、フィールドをJSON出力に含めるかどうかを制御することもできます。 大きなJSONオブジェクトや、常に含めたくないオプションのフィールドがある場合があるため、これらのフィールドを省略すると便利です。 フィールドが空のときに省略されるかどうかの制御は、json
構造体タグのomitempty
オプションを介して行われます。
次に、プログラムを更新してNullStringValue
フィールドをomitempty
にし、同じオプションでEmptyString
という新しいフィールドを追加します。
main.go
... type myJSON struct { ... NullStringValue *string `json:"nullStringValue,omitempty"` NullIntValue *int `json:"nullIntValue"` EmptyString string `json:"emptyString,omitempty"` } ...
これで、myJSON
がマーシャリングされるときに、EmptyString
フィールドとNullStringValue
フィールドの両方の値が空の場合、それらのフィールドは出力から除外されます。
変更を保存したら、go run
を使用してプログラムを実行します。
go run main.go
出力は次のようになります。
Outputjson data: {"intValue":1234,"boolValue":true,"stringValue":"hello!","dateValue":"2022-03-02T09:10:00Z","objectValue":{"arrayValue":[1,2,3,4]},"nullIntValue":4321}
今回の出力では、nullStringValue
フィールドが表示されなくなります。 nil
の値を持つことで空と見なされるため、omitempty
オプションはそれを出力から除外しました。 また、新しいemptyString
フィールドも含まれていないことがわかります。 emptyString
の値はnil
ではありませんが、文字列のデフォルトの""
値は空であると見なされるため、同様に除外されました。
このセクションでは、struct
タイプを使用して、map
タイプの代わりにjson.Marshal
でJSONデータを生成するようにプログラムを更新しました。 また、JSON出力から空のフィールドを省略するようにプログラムを更新しました。
ただし、プログラムをJSONエコシステムにうまく適合させるには、JSONデータを生成するだけでは不十分です。 また、リクエストに応じて送信されるJSONデータ、またはリクエストを送信する他のシステムを読み取ることができる必要があります。 encoding/json
パッケージは、JSONデータをさまざまなGoタイプにデコードする方法も提供します。 次のセクションでは、JSON文字列をGomap
タイプにデコードするようにプログラムを更新します。
マップを使用したJSONの解析
このチュートリアルの最初のセクションで、JSONデータを生成するための柔軟な方法としてmap[string]interface{}
を使用したのと同様に、JSONデータを読み取るための柔軟な方法としても使用できます。 json.Unmarshal
関数は、本質的にjson.Marshal
関数の反対であり、JSONデータを取得してGoデータに変換し直します。 json.Unmarshal
にJSONデータと、マーシャリングされていないデータを入れるGo変数を指定すると、error
値を返すか、[ X181X]成功した場合のエラー値。 このセクションでは、json.Unmarshal
関数を使用して、事前定義されたstring
値からmap
変数にJSONデータを読み取るようにプログラムを更新します。 また、プログラムを更新して、Goデータを出力に出力します。
次に、json.Unmarshal
を使用してJSONデータをmap[string]interface{}
にアンマーシャリングするようにプログラムを更新します。 まず、元のdata
変数をJSON文字列を含むjsonData
変数に置き換えます。 次に、新しいdata
変数をmap[string]interface{}
として宣言して、JSONデータを受信します。 最後に、これらの変数でjson.Unmarshal
を使用して、JSONデータにアクセスします。
main.go
ファイルを開き、main
関数の行を次のように置き換えます。
main.go
... func main() { jsonData := ` { "intValue":1234, "boolValue":true, "stringValue":"hello!", "dateValue":"2022-03-02T09:10:00Z", "objectValue":{ "arrayValue":[1,2,3,4] }, "nullStringValue":null, "nullIntValue":null } ` var data map[string]interface{} err := json.Unmarshal([]byte(jsonData), &data) if err != nil { fmt.Printf("could not unmarshal json: %s\n", err) return } fmt.Printf("json map: %v\n", data) }
このアップデートでは、jsonData
変数が生の文字列リテラルを使用して設定され、宣言が複数行にまたがって読みやすくなっています。 data
をmap[string]interface{}
として宣言した後、jsonData
とdata
をjson.Unmarshal
に渡して、JSONデータを[にアンマーシャリングします。 X128X]変数。
この関数には[]byte
タイプが必要であり、jsonData
は最初はstring
タイプ。 これが機能するのは、Goのstring
を[]byte
に、またはその逆に変換できるためです。 data
変数が参照として渡されているのは、json.Unmarshal
がデータを変数に入れるために、変数がメモリ内のどこに格納されているかへの参照が必要だからです。
最後に、JSONデータがdata
変数にアンマーシャリングされたら、fmt.Printf
を使用して画面に出力します。
更新したプログラムを実行するには、変更を保存し、go run
を使用してプログラムを実行します。
go run main.go
出力は次のようになります。
Outputjson map: map[boolValue:true dateValue:2022-03-02T09:10:00Z intValue:1234 nullIntValue:<nil> nullStringValue:<nil> objectValue:map[arrayValue:[1 2 3 4]] stringValue:hello!]
今回の出力は、JSON変換のGo側を示しています。 map
値があり、JSONデータのさまざまなフィールドが含まれています。 JSONデータのnull
フィールドもマップに表示されます。
これで、Goデータはmap[string]interface{}
にあるため、データの使用に必要な作業が少しあります。 目的のstring
キー値を使用して、map
から値を取得する必要があります。次に、受け取った値が[Xとして返されるため、期待した値であることを確認する必要があります。 X199X]値。
これを行うには、main.go
ファイルを開き、プログラムを更新して、次のコードでdateValue
フィールドを読み取ります。
main.go
... func main() { ... fmt.Printf("json map: %v\n", data) rawDateValue, ok := data["dateValue"] if !ok { fmt.Printf("dateValue does not exist\n") return } dateValue, ok := rawDateValue.(string) if !ok { fmt.Printf("dateValue is not a string\n") return } fmt.Printf("date value: %s\n", dateValue) }
このアップデートでは、data["dateValue"]
を使用してrawDateValue
をinterface{}
タイプとして取得し、ok
変数を使用して[X129X ]フィールドはmap
にあります。
次に、 type assertion を使用して、rawDateValue
のタイプが実際にはstring
値であることを表明し、それを変数dateValue
に割り当てます。 その後、ok
変数を再度使用して、アサーションが成功したことを確認します。
最後に、fmt.Printf
を使用してdateValue
を印刷します。
更新したプログラムを再度実行するには、変更を保存し、go run
を使用して実行します。
go run main.go
出力は次のようになります。
Outputjson map: map[boolValue:true dateValue:2022-03-02T09:10:00Z intValue:1234 nullIntValue:<nil> nullStringValue:<nil> objectValue:map[arrayValue:[1 2 3 4]] stringValue:hello!] date value: 2022-03-02T09:10:00Z
map
から抽出されてstring
値に変換されたdateValue
フィールドを示すdate value
行が表示されます。
このセクションでは、json.Unmarshal
関数とmap[string]interface{}
変数を使用して、JSONデータをGoデータにアンマーシャリングするようにプログラムを更新しました。 次に、プログラムを更新して、GoデータからdateValue
の値を抽出し、画面に出力しました。
ただし、この更新では、map[string]interface{}
を使用してGoでJSONをアンマーシャリングすることの欠点の1つが示されています。 Goは、各フィールドがどのタイプのデータであるかを知らないため(interface{}
であることがわかっているだけです)、データを非整列化するためにできる最善のことは、最善の推測を行うことです。 つまり、dateValue
フィールドのtime.Time
のような複雑な値は、マーシャリングを解除できず、string
としてのみアクセスできます。 この方法でmap
の任意の数値にアクセスしようとすると、同様の問題が発生します。 json.Unmarshal
は、番号がint
、float
、int64
などのいずれであるかを認識していないため、推測できる最善の方法です。利用可能な最も柔軟な数値タイプ、float64
にそれを入れることです。
map
を使用してJSONデータをデコードすることは柔軟ですが、データを解釈する際の作業も多くなります。 json.Marshal
関数がstruct
値を使用してJSONデータを生成する方法と同様に、json.Unmarshal
関数はstruct
値を使用してJSONデータを読み取ることができます。 これは、struct
のフィールドの型定義を使用して、JSONデータをどの型として解釈するかを決定することにより、map
を使用する際の型アサーションの複雑さを取り除くのに役立ちます。 次のセクションでは、struct
タイプを使用してこれらの複雑さを取り除くように、プログラムを更新します。
Structを使用したJSONの解析
JSONデータを読んでいるときは、受け取っているデータの構造をすでに知っている可能性があります。 そうしないと、解釈が困難になります。 この構造に関する知識を使用して、データがどのように見えるか、および期待するデータのタイプについてGoにヒントを与えることができます。
前のセクションでは、myJSON
とmyObject
struct
の値を定義し、json
構造体タグを追加して、JSONを生成するときにフィールドに名前を付ける方法をGoに知らせました。 。 これで、同じstruct
値を使用して、使用していたJSON文字列をデコードできます。これは、同じJSONデータをマーシャリングおよびアンマーシャリングする場合に、プログラム内の重複コードを減らすのに役立ちます。 JSONデータのマーシャリングを解除するためにstruct
を使用するもう1つの利点は、各フィールドに期待されるデータのタイプをGoに伝えることができることです。 最後に、Goのコンパイラを使用して、map
値で使用するstring
値のタイプミスを見逃すのではなく、フィールドで正しい名前を使用していることを確認することもできます。 。
次に、main.go
ファイルを開き、data
変数宣言を更新して、myJSON
struct
への参照を使用し、fmt.Printf
をいくつか追加します。 ] myJSON
のさまざまなフィールドのデータを表示する行:
main.go
... func main() { ... var data *myJSON err := json.Unmarshal([]byte(jsonData), &data) if err != nil { fmt.Printf("could not unmarshal json: %s\n", err) return } fmt.Printf("json struct: %#v\n", data) fmt.Printf("dateValue: %#v\n", data.DateValue) fmt.Printf("objectValue: %#v\n", data.ObjectValue) }
以前にstruct
タイプを定義したので、struct
へのアンマーシャリングをサポートするには、data
フィールドのタイプを更新するだけで済みます。 残りの更新では、struct
自体のデータの一部が表示されます。
次に、更新を保存し、go run
を使用してプログラムを実行します。
go run main.go
出力は次のようになります。
Outputjson struct: &main.myJSON{IntValue:1234, BoolValue:true, StringValue:"hello!", DateValue:time.Date(2022, time.March, 2, 9, 10, 0, 0, time.UTC), ObjectValue:(*main.myObject)(0x1400011c180), NullStringValue:(*string)(nil), NullIntValue:(*int)(nil), EmptyString:""} dateValue: time.Date(2022, time.March, 2, 9, 10, 0, 0, time.UTC) objectValue: &main.myObject{ArrayValue:[]int{1, 2, 3, 4}}
今回の出力には、注意すべき点がいくつかあります。 json struct
行とdateValue
行の両方で、JSONデータの日付値がtime.Time
値([X155X ] formatは、%#v
がフォーマット動詞として使用されている場合に表示されるものです。 GoはmyJSON
のDateValue
フィールドでtime.Time
タイプを確認できたため、string
値も解析できました。
もう1つ注意すべき点は、EmptyString
は、元のJSONデータに含まれていなくても、json struct
行に表示されることです。 JSONアンマーシャリングに使用されるstruct
にフィールドが含まれていて、アンマーシャリングされるJSONデータに含まれていない場合、そのフィールドはそのタイプのデフォルト値に設定され、無視されます。 このようにして、プロセスのどちらの側にもフィールドが存在しない場合にエラーが発生することを心配することなく、JSONデータが持つ可能性のあるすべてのフィールドを安全に定義できます。 NullStringValue
とNullIntValue
の両方も、値がnull
であるとJSONデータが示しているため、デフォルト値のnil
に設定されますが、これらも次のように設定されます。 nil
これらのフィールドがJSONデータから除外されていた場合。
emptyString
フィールドがJSONデータから欠落しているときにstruct
のEmptyString
フィールドがjson.Unmarshal
によって無視されたのと同様に、逆も当てはまります。 フィールドがJSONデータに含まれているが、Go struct
に対応するフィールドがない場合、そのJSONフィールドは無視され、解析は次のJSONフィールドに進みます。 このように、読み取っているJSONデータが非常に大きく、プログラムがそれらのフィールドの少数のみを考慮している場合は、関心のあるフィールドのみを含むstruct
を作成することを選択できます。 struct
で定義されていないJSONデータに含まれるフィールドはすべて無視され、GoのJSONパーサーは次のフィールドに進みます。
これが実際に動作することを確認するには、main.go
ファイルをもう一度開き、jsonData
を更新して、myJSON
に含まれていないフィールドを含めます。
main.go
... func main() { jsonData := ` { "intValue":1234, "boolValue":true, "stringValue":"hello!", "dateValue":"2022-03-02T09:10:00Z", "objectValue":{ "arrayValue":[1,2,3,4] }, "nullStringValue":null, "nullIntValue":null, "extraValue":4321 } ` ... }
JSONデータを追加したら、ファイルを保存し、go run
を使用して実行します。
go run main.go
出力は次のようになります。
Outputjson struct: &main.myJSON{IntValue:1234, BoolValue:true, StringValue:"hello!", DateValue:time.Date(2022, time.March, 2, 9, 10, 0, 0, time.UTC), ObjectValue:(*main.myObject)(0x14000126180), NullStringValue:(*string)(nil), NullIntValue:(*int)(nil), EmptyString:""} dateValue: time.Date(2022, time.March, 2, 9, 10, 0, 0, time.UTC) objectValue: &main.myObject{ArrayValue:[]int{1, 2, 3, 4}}
GoはJSONデータのextraValue
フィールドを無視して続行するため、この出力と前の出力の間に違いは見られないはずです。
このセクションでは、JSONデータをアンマーシャリングするために以前に定義したstruct
タイプを使用するようにプログラムを更新しました。 Goがtime.Time
値を解析し、struct
タイプで定義されているがJSONデータでは定義されていないEmptyString
フィールドを無視する方法を確認しました。 また、JSONデータにフィールドのサブセットのみを定義した場合でも、Goが安全にデータの解析を続行することを確認するために、JSONデータにフィールドを追加しました。
結論
このチュートリアルでは、Goの標準ライブラリにあるencoding/json
パッケージを使用するための新しいプログラムを作成しました。 まず、json.Marshal
関数とmap[string]interface{}
タイプを使用して、柔軟な方法でJSONデータを作成しました。 次に、json
構造体タグでstruct
タイプを使用するようにプログラムを更新し、json.Marshal
で一貫性のある信頼できる方法でJSONデータを生成しました。 その後、json.Unmarshal
関数とmap[string]interface{}
タイプを使用して、JSON文字列をGoデータにデコードしました。 最後に、json.Unmarshal
関数で以前に定義したstruct
型を使用して、これらのstruct
フィールドに基づいてGoに解析と型変換を実行させました。
encoding/json
パッケージを使用すると、インターネットで利用可能な多くのAPIと対話して、人気のあるWebサイトとの独自の統合を作成できます。 また、独自のプログラムのGoデータを保存できる形式に変換し、後でロードして、プログラムが中断したところから続行することもできます。
このチュートリアルで使用した関数に加えて、 encoding / json パッケージには、JSONとの対話に使用できる他の便利な関数とタイプが含まれています。 たとえば、 json.MarshalIndent 関数を使用して、トラブルシューティングのためにJSONデータをきれいに印刷することができます。
このチュートリアルは、 DigitalOcean How to Code inGoシリーズの一部でもあります。 このシリーズでは、Goの初めてのインストールから、言語自体の使用方法まで、Goに関する多くのトピックを取り上げています。