Go言語 jsonタグ
はじめに
このページではGo言語での以下の内容について記述します。
- JSONタグの基本
- オプションタグ
- JSONのエンコードとデコード
GolangのJSONタグとは
Golangの構造体フィールドにタグを付与することで、JSONエンコード・デコード時にフィールドがどのようにマッピングされるかを制御できます。特にencoding/json
パッケージを使用してデータを操作する際に、非常に役立ちます。
基本的なJSONタグの使い方
Golangの構造体にJSONタグを追加することで、JSONのキー名や挙動をカスタマイズできます。タグの基本的な形式は次の通りです。
type 構造体名 struct {
フィールド名 型 `json:"キー名,オプション"`
}
例えば、次のように使います。
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
この場合、ID
フィールドは"id"
というキーに、Name
フィールドは"name"
というキーにそれぞれマッピングされます。
JSONタグのオプション一覧
GolangのJSONタグには、フィールドのエンコードやデコードに影響を与えるいくつかのオプションがあります。以下は代表的なオプションの一覧です。
omitempty
1. omitempty
は、フィールドが「ゼロ値」である場合に、そのフィールドをJSON出力から除外します。ゼロ値は、型ごとに異なります。例えば、整数型は0
、文字列型は""
(空文字)、スライスはnil
がゼロ値に該当します。
type User struct {
ID int `json:"id"`
Name string `json:"name,omitempty"`
}
省略されるゼロ値
- 数値型:
0
- 文字列型:
""
(空文字) - ポインタ型:
nil
- スライス、マップ、チャネル、インターフェース型:
nil
- ブール型:
false
このオプションは、データが必要でないときに出力されるJSONをコンパクトに保つのに役立ちます。
例: フィールドの値がゼロ値のとき
{
"id": 1
}
-
(ハイフン)
2. JSONタグに"-"
を指定すると、そのフィールドはエンコードおよびデコードの対象外になります。つまり、JSONに出力されません。
type User struct {
ID int `json:"id"`
Name string `json:"-"`
}
"-"
を使用
例: {
"id": 1
}
この場合、Name
フィールドはJSON出力には含まれません。
string
3. string
オプションを付けると、数値やブール値などの非文字列型のフィールドを、文字列としてエンコード・デコードします。例えば、整数型の値をJSONでは文字列として表現する場合に使います。
type User struct {
ID int `json:"id,string"`
}
例: 数値を文字列として出力
{
"id": "1"
}
数値型のID
が文字列としてエンコードされています。
omitempty,string
の組み合わせ
4. omitempty
とstring
を組み合わせることも可能です。この場合、ゼロ値のときはフィールドを出力せず、ゼロ値でないときは数値などを文字列として出力します。
type User struct {
Age int `json:"age,omitempty,string"`
}
omitempty,-
の組み合わせ
5. 特殊なケースですが、omitempty,-
のように組み合わせることもできます。これはあまり使用されませんが、ゼロ値でない場合も、そのフィールドが出力されないことを意味します。
type User struct {
Age int `json:"age,omitempty,-"`
}
この場合、Age
は常に出力されません。
6. カスタムタグ名
JSONタグの"キー名"
部分を省略すると、フィールド名がそのままキー名として使われます。以下の例ではjson:"-"
で非表示にするフィールドと、omitempty
で省略されるフィールドの例を示します。
type User struct {
ID int `json:"id"`
Username string `json:"name,omitempty"`
Password string `json:"-"`
}
例: 出力結果
{
"id": 1,
"name": "John"
}
この場合、Password
フィールドは出力されません。
オプションのまとめ
オプション | 説明 |
---|---|
omitempty |
フィールドがゼロ値の場合、そのフィールドをJSON出力から除外する |
- |
フィールドをエンコードおよびデコードの対象から除外 |
string |
数値やブール値を文字列としてエンコード・デコードする |
omitempty,string |
ゼロ値の時はフィールドを省略し、値がある場合は文字列としてエンコードする |
omitempty,- |
ゼロ値であっても常にフィールドを出力しない(特殊なケース) |
カスタムキー名 | 指定された名前をJSONのキー名にする |
Golangでのエンコードとデコード
Golangでは、標準ライブラリのencoding/json
パッケージを使って、構造体やマップなどのデータをJSON形式にエンコードしたり、JSONデータをデコードして構造体にマッピングすることができます。
JSONエンコード
構造体をJSONにエンコードする方法
Golangでは、構造体をJSON形式に変換するためにjson.Marshal()
を使用します。次の例では、User
構造体をエンコードしています。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email_address,omitempty"`
}
func main() {
user := User{
ID: 1,
Name: "John Doe",
Email: "john.doe@example.com",
}
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("エンコードエラー:", err)
return
}
fmt.Println(string(jsonData))
}
エンコード結果
{
"id": 1,
"name": "John Doe",
"email_address": "john.doe@example.com"
}
json.Marshal()
は、構造体をJSON文字列にエンコードし、[]byte
型を返します。[]byte
をstring
型に変換して表示しています。
エンコードでのポイント
- フィールド名が大文字で始まるもの(エクスポート可能なフィールド)だけがエンコードされます。
-
omitempty
オプションを使用すると、ゼロ値のフィールドはJSON出力に含まれません。
フォーマットされたJSONを出力する方法
json.MarshalIndent()
を使用すると、フォーマットされた(インデントされた)JSONを出力することができます。
jsonData, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(jsonData))
このようにすると、次のように整形されたJSONが出力されます。
{
"id": 1,
"name": "John Doe",
"email_address": "john.doe@example.com"
}
JSONデコード
JSONを構造体にデコードする方法
JSONデータをGoの構造体に変換するには、json.Unmarshal()
を使用します。次の例では、JSON文字列をUser
構造体にデコードしています。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email_address"`
}
func main() {
jsonStr := `{"id":1,"name":"John Doe","email_address":"john.doe@example.com"}`
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
fmt.Println("デコードエラー:", err)
return
}
fmt.Printf("ID: %d, Name: %s, Email: %s\n", user.ID, user.Name, user.Email)
}
デコード結果
ID: 1, Name: John Doe, Email: john.doe@example.com
デコードのポイント
-
json.Unmarshal()
では、JSONデータを構造体やマップにデコードできます。構造体をデコードする場合、ポインタを渡す必要があります(&user
のように)。 - JSONのキーが構造体フィールドに存在しない場合、そのフィールドは初期値(ゼロ値)になります。
- JSONのフィールド名と構造体フィールド名はタグを使ってマッピングされます。タグがない場合は、デフォルトでフィールド名が使われます。
マップを使ったエンコード・デコード
マップをJSONにエンコードする
構造体ではなく、マップもJSONにエンコードできます。例えば、次のようなマップをエンコードします。
package main
import (
"encoding/json"
"fmt"
)
func main() {
data := map[string]interface{}{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
}
jsonData, err := json.Marshal(data)
if err != nil {
fmt.Println("エンコードエラー:", err)
return
}
fmt.Println(string(jsonData))
}
マップのエンコード結果
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}
JSONをマップにデコードする
次に、JSON文字列をマップにデコードします。
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonStr := `{"id":1,"name":"John Doe","email":"john.doe@example.com"}`
var data map[string]interface{}
err := json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
fmt.Println("デコードエラー:", err)
return
}
fmt.Println(data)
}
デコード結果
map[id:1 name:John Doe email:john.doe@example.com]
構造体とマップの比較
構造体のメリット
- 型が決まっているため、データの扱いが安全で、予測可能。
- タグを使ってJSONキー名やオプションを指定できる。
マップのメリット
- 柔軟性が高く、任意のキー・値のペアを扱える。
- フィールドが決まっていないJSONデータを扱いやすい。
エンコードとデコードのエラーハンドリング
エンコードやデコード時にはエラーが発生する可能性があるため、エラーハンドリングは重要です。次のように、err
をチェックしてエラー処理を行います。
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("エンコードエラー:", err)
}
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
fmt.Println("デコードエラー:", err)
}
まとめ
Golangでは、json.Marshal()
とjson.Unmarshal()
を使用して簡単に構造体やマップをJSONにエンコード・デコードすることができます。JSONタグを活用して、キー名のカスタマイズや省略処理も可能です。エンコードとデコードの方法を理解することで、効率的なデータ操作が可能になります。
参考文献:
Discussion