在Go 中,匿名結構字段通常被封送,就好像它們的內部導出字段是外部結構中的字段一樣。然而,當使用介面{}類型的匿名成員封送結構時,這可能會導致意外行為。
考慮以下範例:
<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中文網其他相關文章!