首頁 > 後端開發 > Golang > 如何在 Go JSON 序列化中壓平匿名介面欄位?

如何在 Go JSON 序列化中壓平匿名介面欄位?

Susan Sarandon
發布: 2024-10-29 06:52:02
原創
530 人瀏覽過

How to Flatten Anonymous Interface Fields in Go JSON Serialization?

在Go 中使用匿名成員扁平化JSON 結構

在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中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板