从平面 json 到嵌套结构的自定义解组

Custom unmarshalling from flat json to nested struct

假设我有两个这样相关的结构:

type SecretUser struct {
    UserInfo `json:"userInfo"`
    Password string `json:"password"`
}

type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}

我收到了一个 JSON 这种形式:

{
    "firstName": "nice",
    "lastName":"guy",
    "email":"nice@guy.co.uk",
    "password":"abc123"
}

我想将此 JSON 解组为一个 SecretUser。有没有比这样做更好的方法?

func (u *User) UnmarshalJSON(data []byte) error {
    var objmap map[string]*json.RawMessage
    var password string
    var err error

    err = json.Unmarshal(data, &objmap)
    if err != nil {
        return err
    }

    if err := json.Unmarshal(data, &u.UserInfo); err != nil {
        return err
    }
    
    err = json.Unmarshal(*objmap["password"], &password)
    if err != nil {
        return err
    }

    u.Password = password
    return nil
}

基本上,我将 JSON 部分解组为 UserInfo 结构,然后再次读取它以提取密码。我不想创建另一个结构来干净地解组此 JSON 或使用外部库(除非它是标准的一部分)。是否有更多 clean/efficient 方法可以做到这一点,而无需阅读 JSON 两次或从地图手动设置每个字段?

只需将 UserData 包含到 SecretUser 结构中,不要为其指定 json 标记。

type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}

type SecretUser struct {
    UserInfo
    Password string `json:"password"`
}

func main() {
    data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
    var u SecretUser
    json.Unmarshal(data, &u)
    fmt.Println(u)
}

Go Play Space example