Go では、通常、匿名の構造体フィールドは、エクスポートされた内部フィールドが外部構造体のフィールドであるかのようにマーシャリングされます。ただし、これにより、interface{} 型の匿名メンバーを使用して構造体をマーシャリングするときに予期しない動作が発生する可能性があります。
次の例を考えてみましょう。
<code class="go">type User struct { Id int `json:"id"` Name string `json:"name"` } type Session struct { Id int `json:"id"` UserId int `json:"userId"` } type Anything interface{} type Hateoas struct { Anything Links map[string]string `json:"_links"` } func MarshalHateoas(subject interface{}) ([]byte, error) { h := &Hateoas{subject, make(map[string]string)} switch s := subject.(type) { case *User: h.Links["self"] = fmt.Sprintf("http://user/%d", s.Id) case *Session: h.Links["self"] = fmt.Sprintf("http://session/%d", s.Id) } return json.MarshalIndent(h, "", " ") } func main() { u := &User{123, "James Dean"} s := &Session{456, 123} json, err := MarshalHateoas(u) if err != nil { panic(err) } else { fmt.Println("User JSON:") fmt.Println(string(json)) } json, err = MarshalHateoas(s) if err != nil { panic(err) } else { fmt.Println("Session JSON:") fmt.Println(string(json)) } }</code>
実行時このコードでは、結果の JSON は期待どおりではありません:
<code class="json">User JSON: { "Anything": { "id": 123, "name": "James Dean" }, "_links": { "self": "http://user/123" } } Session JSON: { "Anything": { "id": 456, "userId": 123 }, "_links": { "self": "http://session/456" } }</code>
ご覧のとおり、匿名メンバー Anything は JSON 内の名前付きフィールドとして扱われますが、これは意図した動作ではありません。
匿名メンバーをフラット化し、目的の JSON 構造を実現するには、reflect パッケージを使用して構造体のフィールドをループし、それらを map[string]interface{} にマッピングします。これにより、新しいフィールドを導入することなく、元の構造体のフラットな構造を維持できます。
更新されたコードは次のとおりです。
<code class="go">import ( "encoding/json" "fmt" "reflect" ) // ... (rest of the code remains the same) func MarshalHateoas(subject interface{}) ([]byte, error) { links := make(map[string]string) out := make(map[string]interface{}) subjectValue := reflect.Indirect(reflect.ValueOf(subject)) subjectType := subjectValue.Type() for i := 0; i < subjectType.NumField(); i++ { field := subjectType.Field(i) name := subjectType.Field(i).Name out[field.Tag.Get("json")] = subjectValue.FieldByName(name).Interface() } switch s := subject.(type) { case *User: links["self"] = fmt.Sprintf("http://user/%d", s.Id) case *Session: links["self"] = fmt.Sprintf("http://session/%d", s.Id) } out["_links"] = links return json.MarshalIndent(out, "", " ") }</code>
この変更により、結果の JSON は正しくフラット化されます。
<code class="json">User JSON: { "id": 123, "name": "James Dean", "_links": { "self": "http://user/123" } } Session JSON: { "id": 456, "userId": 123, "_links": { "self": "http://session/456" } }</code>
以上がGo JSON シリアル化で匿名インターフェイス フィールドをフラット化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。