Go言語のJSONパッケージとMarshalerとUnmarshaler
Go言語では、JSON形式のデータを扱うための機能が標準パッケージの一部として提供されています。その中心にあるのが encoding/json
パッケージです。
このパッケージは、Goのデータ構造をJSONに変換(マーシャリング)したり、JSONをGoのデータ構造に変換(アンマーシャリング)したりするための関数や型を提供しています。
MarshalerとUnmarshaler
Marshaler
と Unmarshaler
は、それぞれJSONへのマーシャリングとJSONからのアンマーシャリングをカスタマイズするためのインターフェースです。
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
これらのインターフェースを実装することで、特定の型に対するJSONの変換方法を自由に定義することができます。これにより、標準の変換ルールだけでは対応できない複雑なケースにも対応することが可能になります。
次のセクションでは、これらのインターフェースを活用した具体的な例を見ていきましょう。
構造体のフィールドを指定の形式でMarshal, Unmarshalする
Go言語では、構造体のフィールドをJSONのキーとしてマーシャリングしたり、JSONのキーから構造体のフィールドにアンマーシャリングしたりする際に、フィールドタグを使用して変換の挙動を制御することができます。
フィールドタグの基本
Goの構造体では、フィールド宣言の後にバッククォート()で囲まれた文字列を書くことで、そのフィールドに対する追加の情報(フィールドタグ)を指定することができます。
encoding/json` パッケージでは、このフィールドタグを利用してJSONのキー名を制御します。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
この例では、Person
構造体の Name
フィールドはJSONでは name
キーとして表現され、Age
フィールドは age
キーとして表現されます。
フィールドタグの応用
フィールドタグでは、さらに詳細な制御も可能です。例えば、JSONに存在しないキーに対応するフィールドを省略したり、逆にフィールドがゼロ値の場合にJSONからそのキーを省略したりすることができます。
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
}
この例では、Age
フィールドに omitempty
オプションが指定されています。これにより、Age
フィールドがゼロ値(この場合は0)のときには、JSONから age
キーが省略されます。
次のセクションでは、配列やスライスのJSON変換について見ていきましょう。
配列やスライスのJSON変換
Go言語では、配列やスライスもJSONとして表現することができます。これらの型は、JSONの配列としてマーシャリングされ、逆にJSONの配列はGoの配列やスライスとしてアンマーシャリングされます。
配列とスライスのマーシャリング
配列やスライスをJSONにマーシャリングするには、json.Marshal
関数を使用します。
nums := []int{1, 2, 3, 4, 5}
jsonBytes, err := json.Marshal(nums)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonBytes)) // Output: [1,2,3,4,5]
この例では、整数のスライスがJSONの配列に変換されています。
配列とスライスのアンマーシャリング
逆に、JSONの配列をGoの配列やスライスにアンマーシャリングするには、json.Unmarshal
関数を使用します。
jsonStr := "[1,2,3,4,5]"
var nums []int
err := json.Unmarshal([]byte(jsonStr), &nums)
if err != nil {
log.Fatal(err)
}
fmt.Println(nums) // Output: [1 2 3 4 5]
この例では、JSONの配列がGoの整数のスライスに変換されています。
次のセクションでは、より複雑なJSONと構造体の変換について見ていきましょう。
複雑なJSON↔構造体の変換
Go言語では、複雑なJSONと構造体の変換も可能です。具体的には、ネストしたJSONや、キーが動的に変わるようなJSONも扱うことができます。
ネストしたJSONの変換
ネストしたJSONは、ネストした構造体に変換することができます。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address struct {
Street string `json:"street"`
City string `json:"city"`
} `json:"address"`
}
この例では、Address
フィールドがネストした構造体として定義されています。これにより、以下のようなJSONを扱うことができます。
{
"name": "John Doe",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
動的なキーの変換
キーが動的に変わるようなJSONは、map[string]T
型(Tは任意の型)に変換することができます。
var m map[string]int
jsonStr := `{"apple": 1, "banana": 2, "cherry": 3}`
err := json.Unmarshal([]byte(jsonStr), &m)
if err != nil {
log.Fatal(err)
}
fmt.Println(m) // Output: map[apple:1 banana:2 cherry:3]
この例では、フルーツの名前をキーとし、その数を値とするJSONを map[string]int
型に変換しています。
以上が、Go言語での複雑なJSON↔構造体の変換についての基本的な説明です。次のセクションでは、独自の変換方式の定義と利用について見ていきましょう。
独自の変換方式の定義と利用
Go言語では、Marshaler
と Unmarshaler
インターフェースを実装することで、独自のJSON変換方式を定義し、利用することができます。
Marshalerの実装
Marshaler
インターフェースは、MarshalJSON() ([]byte, error)
メソッドを要求します。このメソッドを実装することで、型のJSONへのマーシャリング方法をカスタマイズできます。
type MyInt int
func (m MyInt) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d\"", m)), nil
}
この例では、MyInt
型が Marshaler
インターフェースを実装しています。その結果、MyInt
型の値はJSONでは文字列として表現されます。
Unmarshalerの実装
逆に、Unmarshaler
インターフェースは、UnmarshalJSON([]byte) error
メソッドを要求します。このメソッドを実装することで、JSONからのアンマーシャリング方法をカスタマイズできます。
func (m *MyInt) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*m = MyInt(i)
return nil
}
この例では、MyInt
型が Unmarshaler
インターフェースを実装しています。その結果、JSONの文字列から MyInt
型の値を生成することができます。
以上が、Go言語での独自の変換方式の定義と利用についての基本的な説明です。これらの技術を活用することで、様々な形式のJSONデータを効率的に扱うことが可能になります。これらの知識を活かして、Go言語でのJSONの扱い方をマスターしましょう!