Go 言語(以下 golang)で、データのパース用に複数の構造体(以下 struct)を組み合わせたい。
JSON データをパースしたいのですが、JSON 側の仕様が整っていないため、微妙に異なるも、ほぼ同じ struct を複数用意する必要がありました。
シンプルな構造体を組み合わせてダイナミック(動的)に struct を作りたいのですが、ダイナミックと言っても reflection などを使うレベルではなく string フィールドのみで十分なのです。
「golang struct マージ」とググっても、シンプルなタイトルや用途の Qiita 記事がヒットしなかったので、自分のググラビリティとして。
TL; DR (今北産業)
Embedded Struct(構造体の埋め込み)でよかった。
微妙に違う構造の JSON データ
パースしたいデータ例
data1 := `{
“hoge”: “hoge hoge”,
“fuga”: “fuga fuga”
}`
data2 := `{
“hoge”: “hoge hoge hoge”,
“piyo”: “piyo piyo”
}`
組み合わせ用の小さな構造体
type Foo struct {
Hoge string `json:”hoge”`
}
type Bar struct {
Fuga string `json:”fuga”`
}
type Buz struct {
Piyo string `json:”piyo”`
}
適宜パターンを組み合わせてパース
mix := new(struct {
Foo
Bar
})
if err := json.Unmarshal([]byte(data1), mix); err != nil {
panic(err)
}
このパターンは、シンプルな構造のデータをパースする場合には適してますが、メソッドを絡めたり、逆の JSON データ出力(Marshal)といった、ちょっと複雑なことをしようとすると、すぐに限界がきます。
TS; DR
package main
import (
"encoding/json"
"fmt"
)
type Foo struct {
Hoge string `json:"hoge"`
}
type Bar struct {
Fuga string `json:"fuga"`
}
type Buz struct {
Piyo string `json:"piyo"`
}
func main() {
// 微妙に違う JSON データ
data1 := `{
"hoge": "hoge hoge",
"fuga": "fuga fuga"
}`
data2 := `{
"hoge": "hoge hoge hoge",
"piyo": "piyo piyo"
}`
// パターン1をパースしてプリント
mix1 := new(struct {
Foo
Bar
})
if err := json.Unmarshal([]byte(data1), mix1); err != nil {
panic(err)
}
fmt.Println("Mix1:", mix1.Hoge, mix1.Fuga)
// パターン2をパースしてプリント
mix2 := new(struct {
Foo
Buz
})
if err := json.Unmarshal([]byte(data2), mix2); err != nil {
panic(err)
}
fmt.Println("Mix2:", mix2.Hoge, mix2.Piyo)
// Output:
// Mix1: hoge hoge fuga fuga
// Mix2: hoge hoge hoge piyo piyo
}
オンラインで動作をみる @ GoPlayground
参考文献
Embedding | Effective Go @ go.dev
How can I merge two structs in Golang? @ StackOverflow