如何在 Go 中使用不同的 json 标签将 json 从一个结构编组到另一个结构?

How to Marshall json from one struct to another with different json tags in Go?

我正在创建一个 Go 应用程序,它使用来自多个来源的数据,这些来源都具有相似的数据,但结构与其 data/responses 不同。这些响应需要编组到一个通用结构中,然后发送到另一个服务。

常用结构:

type common struct {
   ID         string `json:id`
   GivenName  string `json:given_name`
   FamilyName string `json:family_name`
   Email:     string `json:email`
}

一个回复:

{
   "id": "123",
   "first_name": "john",
   "last_name": "smith",
   "email": "js@mail.com"
}

另一个回复:

{
   "id": "456",
   "first": "larry",
   "last": "smith",
   "email": {
      "primary": "larry@mail.com"
   }
}

如何将具有一种结构的 json 响应编组为具有不同结构的结构?

我觉得你可以根据不同的来源定义不同的结构。然后,把它转化成那个普通的结构。

当添加新源时,此方法灵活、可读且易于实施。

示例代码如下:

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID         string `json:id`
    GiveName   string `json:given_name`
    FamilyName string `json:family_name`
    Email      string `json:email`
}

type UserFromMySQL struct {
    ID        string `json:"id"`
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Email     string `json:"email"`
}

func (u *UserFromMySQL) GetUser() *User {
    return &User{
        ID:         u.ID,
        GiveName:   u.FirstName,
        FamilyName: u.LastName,
        Email:      u.Email,
    }
}

func main() {
    um := new(UserFromMySQL)

    b := []byte(`{
   "id": "123",
   "first_name": "john",
   "last_name": "smith",
   "email": "js@mail.com"
}`)
    err := json.Unmarshal(b, um)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%+v\n", um)
    fmt.Printf("%+v\n", um.GetUser())
}

当然可以通过增加冗余字段来实现,定义user如下:

type Email {
    Primary string `json:"primary"`
}

type User struct {
    ID           string `json:"id"`
    GiveName     string `json:"given_name"`
    FamilyName   string `json:"family_name"`
    FirstName    string `json:"last_name"`
    LastName     string `json:"last_name"`
    Email        string `json:"email"`
}

选择适合你的方式。我更喜欢第一个。

我建议您为您拥有的每个数据分离结构。

Golang 是一种强类型语言,所以每个结构体应该只代表一种数据类型。这不仅消除了 Guam 代码,还减少了其他开发人员需要跟踪一种数据类型的时间,这有时会发生在 Python 等非强类型语言中。

无论如何,如果你真的需要在同一个结构中表示这些数据,你可以像下面这样写。

type User struct {
   ID         string `json:"id,omitempty"`
   GivenName  string `json:"given_name,omitempty"`
   FamilyName string `json:"family_name,omitempty"`
   FirstName  string `json:"first,omitempty"`
   LastName   string `json:"last,omitempty"`
   PlainEmail string `json:"plain_email,omitempty"`
   Email struct{
    Primary string `json:"primary"`
   } `json:"email,omitempty"`
}

在JSON标签中添加omitempty,所以如果结构是用用户类型A创建的,那么类型B的字段将不会在[=28=中表示].但是,我不推荐这种方法,但如果需要,可以采用这种方法。

无论如何,EmailPlainEmail JSON 标签需要分开,否则编译器会混淆。